Di recente ho discusso con alcuni amici su quale dei seguenti 2 metodi è meglio stub restituire risultati o chiamate a metodi all'interno della stessa classe da metodi all'interno della stessa classe.
Questo è un esempio molto semplificato. In realtà le funzioni sono molto più complesse.
Esempio:
public class MyClass
{
public bool FunctionA()
{
return FunctionB() % 2 == 0;
}
protected int FunctionB()
{
return new Random().Next();
}
}
Quindi per testarlo abbiamo 2 metodi.
Metodo 1: utilizzare le funzioni e le azioni per sostituire la funzionalità dei metodi. Esempio:
public class MyClass
{
public Func<int> FunctionB { get; set; }
public MyClass()
{
FunctionB = FunctionBImpl;
}
public bool FunctionA()
{
return FunctionB() % 2 == 0;
}
protected int FunctionBImpl()
{
return new Random().Next();
}
}
[TestClass]
public class MyClassTests
{
private MyClass _subject;
[TestInitialize]
public void Initialize()
{
_subject = new MyClass();
}
[TestMethod]
public void FunctionA_WhenNumberIsOdd_ReturnsTrue()
{
_subject.FunctionB = () => 1;
var result = _subject.FunctionA();
Assert.IsFalse(result);
}
}
Metodo 2: rendere i membri virtuali, derivare la classe e nella classe derivata utilizzare Funzioni e azioni per sostituire la funzionalità Esempio:
public class MyClass
{
public bool FunctionA()
{
return FunctionB() % 2 == 0;
}
protected virtual int FunctionB()
{
return new Random().Next();
}
}
public class TestableMyClass
{
public Func<int> FunctionBFunc { get; set; }
public MyClass()
{
FunctionBFunc = base.FunctionB;
}
protected override int FunctionB()
{
return FunctionBFunc();
}
}
[TestClass]
public class MyClassTests
{
private TestableMyClass _subject;
[TestInitialize]
public void Initialize()
{
_subject = new TestableMyClass();
}
[TestMethod]
public void FunctionA_WhenNumberIsOdd_ReturnsTrue()
{
_subject.FunctionBFunc = () => 1;
var result = _subject.FunctionA();
Assert.IsFalse(result);
}
}
Voglio sapere qual è il migliore e anche PERCHÉ?
Aggiornamento: NOTA: FunctionB può anche essere pubblico
FunctionB
è rotto dal design. new Random().Next()
è quasi sempre sbagliato. Dovresti iniettare l'istanza di Random
. ( Random
è anche una classe mal progettata, che può causare alcuni problemi aggiuntivi)
FunctionA
restituisce un valore booleano ma imposta solo una variabile localex
e non restituisce nulla.