Configurazione
Molti anni fa ho preso uno stile di test unitario che mi è piaciuto molto. In breve, utilizza una classe base per separare Arrangement, Action e Assertion del test in chiamate di metodo separate. A tale scopo, definisci le chiamate al metodo in [Setup] / [TestInitialize] che verranno chiamate prima di ogni esecuzione di test.
[Setup]
public void Setup()
{
before_each(); //arrangement
because(); //action
}
Questa classe base di solito include anche la chiamata [TearDown] quando si utilizza questa configurazione per i test di integrazione.
[TearDown]
public void Cleanup()
{
after_each();
}
Questo spesso si rompe in una struttura in cui le classi di test ereditano da una serie di classi Given che mettono insieme il setup (cioè GivenFoo: GivenBar: WhenDoingBazz) con le Assertion che sono una riga test con un nome descrittivo di ciò che stanno coprendo
[Test]
public void ThenBuzzSouldBeTrue()
{
Assert.IsTrue(result.Buzz);
}
Il problema
Ci sono pochissimi test che racchiudono una singola azione in modo da finire con un sacco di classi così recentemente ho preso la decisione di definire l'azione in una serie di metodi all'interno della classe di test stessa:
[Test]
public void ThenBuzzSouldBeTrue()
{
because_an_action_was_taken();
Assert.IsTrue(result.Buzz);
}
private void because_an_action_was_taken()
{
//perform action here
}
Ciò comporta diversi metodi di "azione" all'interno della classe di test ma consente il raggruppamento di test simili (ad es. class == WhenTestingDifferentWaysToSetBuzz)
La domanda
Qualcun altro ha un modo migliore per separare le tre "A" dei test? La leggibilità dei test è importante per me quindi preferirei che, quando un test fallisce, che la struttura stessa dei test comunichi ciò che ha fallito. Se qualcuno può leggere la struttura di ereditarietà dei test e avere una buona idea del perché il test potrebbe fallire, credo che aggiunga molto valore ai test (cioè GivenClient: GivenUser: WhenModifyingUserPermissions: ThenReadAccessShouldBeTrue).
Sono a conoscenza del Test di accettazione, ma questo è più su un livello di Unità (o serie di unità) con strati limite imbrogliati.
EDIT : la mia domanda chiede se esiste un evento o un altro metodo per eseguire un blocco di codice prima dei singoli test (qualcosa che potrebbe essere applicato a specifici set di test senza che venga applicato a tutti i test all'interno di una classe come [Setup] lo fanno attualmente. Escludendo l'esistenza di questo evento, di cui sono abbastanza certo non esiste, esiste un altro metodo per realizzare la stessa cosa?
L'uso di [Setup] per ogni caso presenta un problema in ogni modo. Qualcosa come [Azione ("Categoria")] (un metodo di installazione che si applica a test specifici all'interno della classe) sarebbe bello ma non riesco a trovare alcun modo per farlo.