Witam wszystkich,
trafiłem do projektu legacy i chciałbym zrefaktorować klasę mającą 800 LoC. Problem jest taki, że nie wiem z jakiej strony podejść do napisania testów do tego potworka :)
Zależności które wchodzą do konstruktora to inne encje, które również wyglądają bardzo podobnie, tj. kilkaset LoC + zagnieżdżone inne encje. Klasa ma dwie metody publiczne, a cała logika jest schowana w prywatnych metodach wołanych z poziomu konstruktorów!
Definicje klas wymaganych przez konstruktor są tak skomplikowane, że nie znalazłem zadowalającego sposobu na przygotowanie setupu dla testu. Nawet gdyby się to udało, to i tak pozostaje multum ścieżek do pokrycia. Dodam, że jest to kluczowa klasa, wykorzystywana w ponad 150 miejscach w solucji.
public class IndexResult
{
private IReadOnlyCollection<PackageCalculationType> _packageCalculationTypes;
private PackageCalculationType _primaryCalculationType = PackageCalculationType.MainValuationMode;
public IndexDefinition IndexDefinition { get; private set; }
public CalculationResultPortfolio Portfolio { get; private set; }
public IReadOnlyCollection<Group> Groups { get; private set; }
public bool IsError { get; private set; }
public string ErrorShortDescription { get; private set; }
public string ErrorDetailedDescription { get; private set; }
public IndexError ErrorCode { get; private set; }
public bool IsForDependentIndex => IndexDefinition.IsConsolidated;
public bool NoPositionFound { get; private set; }
public bool IsActivatedByDependency { get; private set; }
public bool IsDeactivatedByDependency { get; private set; }
public Nominator Nominator { get; private set; }
public IndexResult(IndexDefinition indexDefinition,
IndexPortfolio indexPortfolio,
List<CalculatedGroup> calculatedGroups,
Nominator Nominator,
IndexPositionType positionType,
HashSet<PortfolioWarning> portfolioWarnings,
IReadOnlyCollection<PackageCalculationType> packageCalculationTypes,
PolicyValueSet policyValueSet,
CalculationContext calculationContext = CalculationContext.None,
CalculationSummary previousCalculationSummary = null,
IndexModelPortfolio modelPortfolio = null)
{
IndexDefinition = indexDefinition;
PortfolioWarnings = portfolioWarnings;
ModelPortfolio = modelPortfolio;
Portfolio = new CalculationResultPortfolio(indexPortfolio);
Nominator = Nominator;
PositionType = positionType;
SetPackageCalculationTypes(packageCalculationTypes);
CheckCalculationError();
Groups = CreateGroups(calculatedGroups, policyValueSet, previousCalculationSummary, calculationContext);
SetIndexLevelValue();
Validate();
}
/*
... private methods
*/
public void SetActiveByDependency()
{
IsActivatedByDependency = true;
SetIndexLevelValue();
}
public void SetDeactivateByDependency()
{
IsDeactivatedByDependency = true;
SetIndexLevelValue();
}
}
pełny listening kodu - https://pastebin.com/dyeejsex
Zastanawiałem się nad utworzeniem bezparametrowego konstruktora internal
i zmianą modyfikatorów dostępu metod z private na protected. Następnie utworzyłbym klasę IndexResultTest
która by dziedziczyła po IndexResult
i wołałbym metody prywatne z jej poziomu, coś w stylu
public class IndexResultTest: IndexResult
{
public FooTest(string parameter) => Foo(parameter); //private method
}
Oczywiście, że wolałbym testować tylko publiczne api i nie zmieniać kodu produkcyjnego na potrzeby testów. Czy jednak w tej sytuacji mam inne wyjście niż testowanie prywatnych metod i krok po kroczku wydzielanie logiki do osobnych klas?
W jaki sposób Wy byście podeszli do tematu? Będę wdzięczny za każdą odpowiedź.
W szczególności liczę na podpowiedzi od @jarekr000000 @somekind @Shalom @Charles_Ray @neves @Afish