Ecco come avrei scritto uno di un paio di test di unità per un tale fabbrica (con xUnit.net):
[Fact]
public void CreateReturnsInstanceWithCorrectParam1()
{
var sut = new FooFactory();
var expected = new object();
var actual = sut.Create(expected, new object());
var concrete = Assert.IsAssignableFrom<Foo>(actual);
Assert.Equal(expected, concrete.Object1);
}
vuol rompere l'incapsulamento? Sì e no ... un po '. L'incapsulamento non riguarda solo l'occultamento dei dati, ma soprattutto l'protecting the invariants of objects.
Supponiamo che Foo espone questa API pubblica:
public class Foo : IFoo
{
public Foo(object param1, object param2);
public void MethodDefinedByInterface();
public object Object1 { get; }
}
Mentre la proprietà Object1
leggermente viola la Law of Demeter, non pasticciare con le invarianti della classe perché è di sola lettura.
Inoltre, la proprietà Object1
fa parte della classe Foo concreto - non l'interfaccia IFoo:
public interface IFoo
{
void MethodDefinedByInterface();
}
Una volta ci si rende conto che in un API loosely coupled, concrete members are implementation details, tali proprietà in calcestruzzo di sola lettura solo hanno un impatto molto basso sull'incapsulamento. Pensare in questo modo:
Il costruttore pubblico Foo è anche una parte delle API della classe Foo concreta, in modo solo controllando l'API pubblica, si apprende che param1
e param2
sono parte della classe. In un certo senso, questo già "rompe l'incapsulamento", quindi rendere ogni parametro disponibile come proprietà di sola lettura sulla classe concreta non cambia molto.
Tali proprietà offrono il vantaggio che ora possiamo testare unitamente la forma strutturale della classe Foo restituita dalla fabbrica.
Questo è molto più facile che dover ripetere una serie di test di unità comportamentali che, dobbiamo presumere, coprono già la classe Foo concreta. È quasi una prova logica:
- Dai test della classe di calcestruzzo Foo sappiamo che utilizza/interagisce correttamente con i parametri del costruttore.
- Da questi test sappiamo anche che il parametro del costruttore è esposto come proprietà di sola lettura.
- Da un test di FooFactory sappiamo che restituisce un'istanza della classe Foo concreta.
- Inoltre, dai test del metodo Create sappiamo che i suoi parametri sono passati correttamente al costruttore Foo.
- Q.E.D.
I test di unità devono dipendere dal requisito funzionale e dalle aspettative sul componente sottoposto a test. Non vedo alcun valore di unità testare quella classe senza il resto del contesto. – ivowiblo
@ivowiblo Penso che tu stia confondendo i test unitari con i test in stile BDD. Se non scrivi un test per questa unità, come fai a sapere se funziona? –
effettua il test dell'unità, ma cosa testerai? qual è l'aspettativa per quell'unità? Ho detto che non vedo il valore di fare un test unitario di quella classe senza sapere altro. Fare test unitari solo per fare test unitari non ha alcun senso. I test (unità, comportamenti, funzionalità complete, qualunque cosa tu voglia) devono essere sempre guidati da aspettative e requisiti. Altrimenti, è solo snobismo (se questa parola esiste). – ivowiblo