Diciamo, per esempio, che voglio testare che un avviso è mostrato sul cruscotto di un'auto solo quando il motore è rotto.
Il metodo che implementa questa funzionalità potrebbe avere il seguente aspetto:
class Dashboard {
function showWarningIfEngineIsBroken() {
if ($this->engine->isBroken()) {
$this->showWarning = true;
}
}
Diciamo che ci sono 10 scenari in cui $this->engine->isBroken()
restituirebbe true
. Durante il test del dashboard, vorrei assicurarmi che la spia si accenda in uno di questi scenari. Quindi una cosa che potrei fare è creare una classe di test come questa:
class DashboardTest {
function showsWarningIfEngineIsBrokenBecauseOfReasonA() { ... }
function showsWarningIfEngineIsBrokenBecauseOfReasonB() { ... }
function showsWarningIfEngineIsBrokenBecauseOfReasonC() { ... }
// etc.
}
Questo non è un problema, fino a quando voglio anche testare che le porte si sbloccano automaticamente non appena il motore si rompe. Poiché ciò creerebbe molti test "duplicati":
class DoorTest {
function unlocksDoorIfEngineIsBrokenBecauseOfReasonA() { ... }
function unlocksDoorIfEngineIsBrokenBecauseOfReasonB() { ... }
function unlocksDoorIfEngineIsBrokenBecauseOfReasonC() { ... }
// etc.
}
Una soluzione sarebbe testare Engine::isBroken()
invece, e nel test per Dashboard e Door, verifica solo cosa succede se isBroken
restituisce true
o false
:
class EngineTest {
function isBrokenReturnsTrueIfEngineIsBrokenBecauseOfReasonA() { ... }
function isBrokenReturnsTrueIfEngineIsBrokenBecauseOfReasonB() { ... }
function isBrokenReturnsTrueIfEngineIsBrokenBecauseOfReasonC() { ... }
// etc.
}
class DashboardTest {
function showsWarningIfEngineIsBroken() {
$stubEngine = ...; // some stub of engine that returns true for 'isBroken'
$dashboard = new Dashboard($stubEngine);
$dashboard->showWarningIfEngineIsBroken();
$this->assertTrue($dashboard->showWarning);
}
}
class DoorTest {
function unlocksIfEngineIsBroken() {
$stubEngine = ...; // some stub of engine that returns true for 'isBroken'
$door = new Door($stubEngine);
$door->unlockIfEngineIsBroken();
$this->assertTrue($door->isUnlocked);
}
}
Quindi alla fine la domanda: a quanto ho capito, i doppi di prova dovrebbero essere usati per evitare che il test dell'unità rallenti o per assicurarsi che rimanga isolato. In questo caso, supponiamo che $engine->isBroken()
sia effettivamente molto veloce e non abbia effetti collaterali. È una buona pratica fermarlo ancora, poiché in realtà voglio solo testare cosa farebbero Door
o Dashboard
quando restituisce true
o false
?