2010-01-14 17 views
10

Was ist Ihrer Meinung nach der sauberste Weg, mehrere Asserts zu einem Ergebnis zu machen? In der Vergangenheit habe ich ihnen alle den gleichen Test gegeben, aber das fängt an, ein bisschen schmutzig zu sein, ich habe gerade mit einer anderen Idee gespielt, die Setup verwendet.Best Practices für mehrere Asserts bei gleichem Ergebnis in C#

[TestFixture] 
public class GridControllerTests 
{ 
    protected readonly string RequestedViewId = "A1"; 

    protected GridViewModel Result { get; set;} 

    [TestFixtureSetUp] 
    public void Get_UsingStaticSettings_Assign() 
    { 
     var dataRepository = new XmlRepository("test.xml"); 

     var settingsRepository = new StaticViewSettingsRepository(); 

     var controller = new GridController(dataRepository, settingsRepository); 

     this.Result = controller.Get(RequestedViewId); 

    } 

    [Test] 
    public void Get_UsingStaticSettings_NotNull() 
    { 
     Assert.That(this.Result,Is.Not.Null); 
    } 

    [Test] 
    public void Get_UsingStaticSettings_HasData() 
    { 
     Assert.That(this.Result.Data,Is.Not.Null); 
     Assert.That(this.Result.Data.Count,Is.GreaterThan(0)); 
    } 

    [Test] 
    public void Get_UsingStaticSettings_IdMatches() 
    { 
     Assert.That(this.Result.State.ViewId,Is.EqualTo(RequestedViewId)); 
    } 

    [Test] 
    public void Get_UsingStaticSettings_FirstTimePageIsOne() 
    { 
     Assert.That(this.Result.State.CurrentPage, Is.EqualTo(1)); 
    } 
} 

Antwort

3

Was müssen Sie halten, ist das Muster der Arrange, Act, Assert (und dann den Test beenden). In Ihrem Fall ist die gesamte Anordnung in der TestFixtureSetUp, wie auch die Aktion getestet wird. Ich würde das ein wenig anders ordnen, es kann unhandlich werden, wenn Sie mehr Tests haben. Wie Dockers bemerkt, sollten schwere Testaufbauten vermieden werden, sie können zu Problemen werden - sie sind "eine Größe für alle" über alle Tests in der Klasse hinweg und können daher schwerer werden, als die meisten Tests benötigen.

Wenn Sie versucht sind, zu einer weiteren Folgeaktion überzugehen und dann mehr zu behaupten, legen Sie dies in einen separaten Test.

Ich habe kein Problem damit, mehrere Behauptungen in den gleichen Test zu setzen, solange sie dazu beitragen, das gleiche zu testen (d. H. Teil derselben "Logical Assertion" sind). In diesem Fall wäre eine beliebige Anzahl von Aussagen über den Inhalt dieses ResultData von mir in Ordnung - sie würden alle denselben Ergebniswert prüfen. Ihre Get_UsingStaticSettings_HasData macht dies sehr deutlich. Es empfiehlt sich, eine eindeutige Fehlernachricht für jede Assertion zu verwenden, damit leichter festgestellt werden kann, welche Assert fehlgeschlagen ist.

Alternativ könnten Sie die entsprechenden Behauptungen in einer einzigen Methode zusammenfassen. Dies ist nützlich für die üblichen DRY-Gründe, wenn Sie es mehr als einmal verwenden, aber ansonsten sehe ich nicht, dass es ein großer Unterschied ist.

In Zusammenfassung
* Wählen Sie eine Aktion pro Test
* Nach der Aktion verwenden, wie viele ähnliche behauptet, wie Sie eine Sache
* Beenden Sie den Test dort testen müssen.

15

Mehrere Behauptungen im selben Test können zu Assertion Roulette führen, also ist dies etwas, von dem Sie immer vorsichtig sein sollten.

Aber Assertion Roulette ist meist ein Problem, wenn die Behauptungen nicht verwandt sind. Wenn sie konzeptionell eng verwandt sind, können viele Aussagen oft als eine einzige Logical Assertions angesehen werden.

In vielen Fällen können Sie das Beste aus beiden Welten erzielen, indem Sie eine solche logische Assertion explizit in einen benutzerdefinierten Typ oder eine benutzerdefinierte Methode einkapseln.

+0

"Logische Behauptungen" ist ein gutes Wort dafür. Es ist interessant, dass das Assertion Roulette-Beispiel im Wesentlichen ein Beispiel dafür ist, "wie man schief geht, indem man nicht Arrange-Act-Assert durchführt". Unterscheiden sich die Konzepte? – Anthony

+0

@Anthony: Die Konzepte unterscheiden sich, obwohl sie eng miteinander verwandt sind. Es ist viel weniger wahrscheinlich, dass Sie den Schmerz von Assertion Roulette spüren, wenn Sie AAA (oder Vier-Phasen-Test, wie xUnit Test Patterns es nennt) fühlen, aber ich würde immer noch variieren, wenn ich völlig unabhängige Zusicherungen im selben Assert-Block habe. –

+3

Die Idee von Assertion Roulette kann in NUnit durch Angabe eines Kommentars in der Assert-Anweisung minimiert werden. Anstatt "Assert.That (condition)" auszuführen, verwende "Assert.That (condition, failureMessage)", wobei "failureMessage" eine Information darüber ist, was der Assert überprüft hat. Dadurch wissen Sie genau, welche Assert-Anweisung in einem Komponententest fehlgeschlagen ist. – Pedro

2

können Sie Oapt verwenden - Ein NUnit Addin für das Ausführen Ein Assert Per Test:

[TestFixture] 
public class GridControllerTests 
{ 
    [TestCase, ForEachAssert] 
    public void Get_UsingStaticSettings_Assign() 
    { 
     var dataRepository = new XmlRepository("test.xml"); 
     var settingsRepository = new StaticViewSettingsRepository(); 
     var controller = new GridController(dataRepository, settingsRepository); 

     var result = controller.Get("A1"); 

     AssertOne.From(
     () => Assert.That(this.Result,Is.Not.Null), 
     () => Assert.That(this.Result.Data,Is.Not.Null), 
     () => Assert.That(this.Result.Data.Count,Is.GreaterThan(0)), 
     () => Assert.That(this.Result.State.ViewId,Is.EqualTo(RequestedViewId)), 
     () => Assert.That(this.Result.State.CurrentPage, Is.EqualTo(1))); 
    } 
} 

Dieses 5 verschiedene Testfälle schaffen wird, eine für jede Assertion.

0

Ich neige dazu, Aussagen nur dann selbst zu machen, wenn sie alleine wertvoll sind. Wenn ich eine Behauptung auf seinem eigenen will, mache ich eine benutzerdefinierte Behauptung:

AssertThatMyObjectMatches(field1, field2, field3, field4, myObject); 

Manchmal aber Ich mag in einem Test mehr als ein Beispiel haben. Ich mache das, wenn die Hälfte des Verhaltens ohne die andere Hälfte keinen Wert hat.

Assert.True(list.IsEmpty()); 

list.Add(new Thing()); 
Assert.False(list.IsEmpty()); 

Andere, darunter ein großer Teil der Ruby-Community, haben eine andere Meinung dazu.Es ist in erster Linie von Dave Astels' Blog-Post gefahren, hier:

http://www.artima.com/weblogs/viewpost.jsp?thread=35578

ich die ‚Eine Behauptung pro Test‘ Methode sehr nützlich für Dinge wie Validierung, wo jeder kleine Aspekt wertvoll ist. Ansonsten mache ich mir nicht so viele Sorgen.

Was für Sie und Ihr Team funktioniert, ist wahrscheinlich der richtige Weg. Ich tendiere zu tun, was einfach und leicht zu ändern scheint, um später das Richtige zu sein, wenn ich eine bessere Vorstellung davon habe, was das Richtige ist. Ich gebe auch viele Given/When/Then Kommentare auf der Einheitsebene in komplexere Beispiele und teile die Klasse auf, wenn es zu komplex wird, um sie zu verstehen.

Der Grund für das Schreiben von Tests auf diese Weise ist nicht so, dass Sie Dinge fangen können, die brechen. Es soll den Menschen helfen, den Code zu verstehen und ihn zu ändern, ohne die Dinge zu verändern.