Let's say you have set up a test that constructs a new Alpha class. At the end of this test, you want to assert that bravo.getCharlie() is equal to some expected String. How should the test get access to this String?
Una delle idee interessanti alla base del "testing driven design": se il tuo test è difficile da scrivere, è un suggerimento che potrebbe esserci un difetto nella progettazione.
Alpha constructs a new Bravo class during its own constructor and exposes no public visibility to it.
Questo è un odore di codice , un suggerimento che qualcosa è andato storto nel tuo codice.
Lo schema di corrispondenza del tuo codice è che hai un effetto collaterale (una scrittura allo stato Charlie) che stai cercando di valutare nel tuo test. In realtà è piuttosto comune avere effetti collaterali che non possono essere letti più tardi (ad esempio, una scrittura sulla console).
Il modello comune per testare una cosa del genere è utilizzare un TestDouble , in modo che tu possa catturare il comportamento.
Ma per che funziona, devi implementare il tuo codice in modo tale che sia apri all'estensione .
Misko Hevery ha scritto una serie di saggi su questioni relative ai costruttori; il suo Top 10 cose che rendono il tuo Codice difficile da testare sarebbe un buon punto di partenza.
Just ask for all of the collaborators you need in your constructor.
L'idea è che mentre questo esempio è chiuso all'estensione
Alpha () {
this.beta = new Beta();
}
rendere la classe aperta all'estensione è semplicemente una questione di ri-organizzazione del codice leggermente.
Alpha (Beta beta) {
this.beta = beta;
}
Tuttavia, se Alpha()
fa parte dell'interfaccia pubblicata , la modifica della firma in questo modo potrebbe rompere la compatibilità con le versioni precedenti. Di solito è una cattiva idea, quindi potresti invece fare questa modifica
Alpha () {
this(new Beta());
}
Alpha (Beta beta) {
this.beta = beta;
}
Il costruttore che è difficile da testare delega il suo lavoro al costruttore che è facile da testare.
Ovviamente, questo a sua volta significa che il costruttore no argument non è coperto da questo test - abbiamo scritto codice migliore, ma i nostri numeri di copertura del test sono diventati "peggiori". Quindi devi decidere come riconciliarlo.
Nel mio caso, ho permesso a me stesso di sentirsi a proprio agio con i consigli di Kent Beck
I get paid for code that works, not for tests, so my philosophy is to test as little as possible to reach a given level of confidence....
e C.A.R. Hoare
There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies....
Il costruttore di default qui incontra la mia barra per "ovviamente nessuna carenza"; il codice è troppo semplice per essere la fonte di un errore.