2017-06-04 3 views
0

Ich habe ein Problem mit sporadisch fehlgeschlagenen Tests bei Verwendung von Nunit 3 und parallelem Testlauf.Nunit paralleler Lebenszyklus und paralleler Test fehlgeschlagen

Wir haben eine Reihe von Tests, die derzeit strukturiert sind als

[TestFixture] 
public class CalculateShipFromStoreShippingCost 
{ 
    private IService_service; 
    private IClient _client; 

    [SetUp] 
    public void SetUp() 
    { 
     _service = Substitute.For<IService>(); 
     _client = new Client(_service); 
    } 

    [Test] 
    public async Task WhenScenario1() 
    { 
     _service.Apply(Args.Any<int>).Returns(1); 
     var result = _client.DoTheThing(); 
     Assert.IsTrue(1,result); 
    } 

    [Test] 
    public async Task WhenScenario2() 
    { 
     _service.Apply(Args.Any<int>).Returns(2); 
     var result = _client.DoTheThing(); 
     Assert.IsTrue(2,result); 
    } 
} 

folgt Manchmal ist der Test nicht als einer der Stellvertreter wird, um den Wert für den anderen Test zurück.

Wie dieser Test strukturiert werden soll, so dass mit Nunit wird es zuverlässig ausgeführt werden, wenn parallel

Antwort

2

getan Sie haben keine Parallelizable Attribute in Ihrem Beispiel gezeigt, so dass ich nehme an, Sie auf einer höheren Ebene das Attribut verwenden am wahrscheinlichsten auf der Versammlung. Andernfalls würde keine parallele Ausführung stattfinden. Da Sie außerdem sagen, dass die Testfälle parallel laufen, haben Sie anscheinend ParallelScope.Children angegeben.

Die beiden Testfälle, die in Ihrem Gerät angezeigt werden, können nicht parallel ausgeführt werden. Sie sollten beachten, dass die SetUp-Methode für jeden der Tests ausgeführt wird. Daher legt jeder der beiden Tests den Wert von _service fest, der Teil des Status der einzelnen Instanz von CalculateShipFromStoreShippingCost ist, die von beiden Tests gemeinsam genutzt wird. Deshalb sehen Sie, dass der "falsche" Ersatz manchmal zurückgegeben wird.

Es ist nicht möglich, dass zwei Testfälle zuverlässig parallel laufen, wenn beide den Zustand des Scheinwerfers ändern. Beachten Sie, dass es egal ist, ob die Zuordnung zu _service in der Testmethode selbst oder in der Methode SetUp erfolgt - beide werden als Teil des Testfalls ausgeführt. Sie müssen also entweder diese beiden Fälle parallel ausführen oder den Status nicht mehr ändern.

Um die Tests nicht parallel auszuführen, fügen Sie einfach zu jeder Testmethode [NonParallelizable] hinzu. Wenn Sie nicht die neueste Framework-Version verwenden, verwenden Sie stattdessen [Parallelizable(ParallelScope.None)]. Ihre anderen Tests werden weiterhin parallel ausgeführt, aber diese beiden nicht.

Alternativ ParallelScope.Fixture auf Baugruppenebene verwenden. Dies führt dazu, dass Fixtures standardmäßig parallel ausgeführt werden, während die einzelnen Testfälle in ihnen nacheinander ausgeführt werden. Wenn Sie ParallelizableAttribute auf Assembly-Ebene verwenden, ist es manchmal am besten, einen konservativeren Ansatz zu wählen, indem Sie innerhalb einiger Fixtures mehr Parallelität hinzufügen, wo es nützlich ist.

Ein völlig anderer Ansatz besteht darin, Ihre Tests statusfrei zu machen. Eliminieren Sie das Element _service, und verwenden Sie einen lokalen Wert innerhalb der Testmethode. Jeder Ihrer Tests füge hinzu, zwei Zeilen wie ...

var service = SubstituteFor<IService>(); 
var client = new Client(service); 

Wie im Beispiel gezeigt, könnte ich mir vorstellen, Sie werden immer sehr wenig Performance-Gewinn von den Betrieb der beiden Verfahren parallel, also würde ich nicht das letzte verwenden Ansatz, es sei denn, ich sah einen bestimmten Leistungsgrund dafür.

Als letzte Anmerkung ... Wenn Sie Ihre Fixtures standardmäßig parallel ausführen (entweder mit einem Assembly-Level-Attribut oder mit Attributen auf jedem Fixture) und kein Parallelizable-Attribut in Ihre Testfälle einfügen, verwendet NUnit ein Optimierung, wobei alle Tests innerhalb der Vorrichtung auf demselben Thread laufen. Diese Einsparung von Kontextänderungen wird oft den Verlust von Leistungsverbesserungen kompensieren, die Sie durch paralleles Ausführen erreichen wollten.

+0

Vielen Dank, dass Sie sich die Zeit genommen haben, eine so detaillierte Antwort zu geben. –

+0

Können Sie den Kommentar erklären? Diese Speicherung von Kontextänderungen wird oft den Verlust von Leistungsverbesserungen kompensieren. ein wenig mehr, nicht ganz sicher, was du hier meinst –

Verwandte Themen