2012-04-10 13 views
4

Ich habe Komponententest-Beispielcode, der im Grunde zwei Threads ausführt: der Hauptthread und ein anderer Thread, den ich starte, der die Testausführung nach einiger Zeit nicht bestehen sollte (das ist im Grunde ein Zeitüberschreitungs-Thread)Wie kann der Komponententest von einem anderen Thread abgebrochen werden?

Code ist wie folgt:

[TestClass] 
public class SomeTestClass 
{ 
    [TestInitialize] 
    public void BeforeTest() 
    { 
     var task = new Task(abortIfTestStilRunsAfterTimeout); 
     task.Start(); 
    } 

    [TestMethod] 
    public void TestMethod() 
    { 
     Thread.Sleep(5000); 
    } 

    private void abortIfTestStilRunsAfterTimeout() 
    { 
     Assert.Fail("timeout passed!"); 

    } 
} 

Nun, ich hatte erwartet, dass die TestMethod() Test nicht bestehen sollte, aber was passiert, ist eigentlich, dass die Aufgabe Thread, der die Assert.Fail Verfahren läuft bekommt eine Ausnahme während der andere Thread läuft weiter und der Test bestanden.

ich nach einem Weg suchen, ist das Testverfahren

+0

Was genau möchten Sie testen? – GolfWolf

+0

Ich habe 100 Testfälle, die auf meinem System laufen. Dieses System ist eine Multithread-Netzwerkanwendung. Wenn die Testfalldosis meine App-Nachrichten in einer korrekten Reihenfolge senden soll und dann auf eine bestimmte Reihenfolge der Antworten wartet. – Tzahi

+0

Wenn also ein Test mehr als 5000 ms dauert, würde es manuell fehlschlagen? – sll

Antwort

2

Sie können versuchen, einen Verweis auf den Testthread zu erhalten und rufen Sie Abort() darauf. Sie können ein Ausnahmezustandsobjekt zu Abort() passieren, die Ihnen eine passieren scheitern Nachricht verwenden können:

[TestClass] 
public class SomeTestClass 
{ 
    Thread testThread; 

    [TestInitialize] 
    public void BeforeTest() 
    { 
     testThread = Thread.CurrentThread; 
     var task = new Task(abortIfTestStilRunsAfterTimeout); 
     task.Start(); 
    } 

    [TestMethod] 
    public void TestMethod() 
    { 
     try 
     { 
      Thread.Sleep(5000); 
     } 
     catch (ThreadAbortException e) 
     { 
      Assert.Fail((string)e.ExceptionState); 
     } 
    } 

    private void abortIfTestStilRunsAfterTimeout() 
    { 
     testThread.Abort("timeout passed!"); 
    } 
} 

Falls Sie nicht wollen, einige 100 Tests modifizieren, können Sie ein Tool wie Postsharp benutzen, um Ihre Testfälle zu ändern, indem Einfügen der try {} catch {} Logik um jeden Testfall für Sie. Es läuft alles darauf hinaus, ein Attribut zu schreiben und Ihre Test-Assembly damit zu dekorieren (es heißt Aspect Oriented Programming und das Framework in PostSharp dafür heißt Laos).

+0

Ich habe diese Methode auch versucht, aber Behauptung Beschreibung wird nicht durch die Verwendung dieser Methode. Ich bin besorgt, dass, wenn jemand anderes ein Problem mit meinen Tests auftreten wird er nicht in der Lage zu verstehen, was diese Abtreibung verursacht – Tzahi

+1

@Tzahi: Sie können eine Nachricht über 'Abort' übergeben - ich habe den Code angepasst. – ChrisWue

+0

es ist besser als der letzte Vorschlag, aber ich muss 100 Tests ändern. Haben sie nichts weniger aufdringlich? – Tzahi

1

Die Idee zum Scheitern verurteilt einfach - Haupttestlogik in einer Task/Thread ausgeführt, und nur Code in der Testmethode/Test initialize setzen Timeout Handhabung. Eine Art Inversion of Control:

// Test class level 
ManualResetEvent mre = new ManualResetEvent(false);         

[TestMethod]  
public void TestMethod()  
{      
    // start waiting task 
    Task task = Task.Factory.StartNew(() => 
     { 
      // Test Body HERE! 
      // ... 

      // if test passed - set event explicitly 
      mre.Set(); 
     }); 


    // Timeout handling logic, 
    // !!! I believe you can put it once in the TestInitialize, just check 
    // whether Assert.Fail() fails the test when called from TestInitialize 
    mre.WaitOne(5000); 

    // Check whether ManualResetEvent was set explicitly or was timeouted 
    if (!mre.WaitOne(0)) 
    { 
     task.Dispose(); 
     Assert.Fail("Timeout"); 
    }     
}      

PS: In Bezug auf WaitOne(0) Trick, MSDN:

Wenn millisecondsTimeout Null ist, wird das Verfahren nicht blockieren. Es testet den Status des Wait-Handles und kehrt sofort zurück.

+0

Auto Rest Events ist in diesem Fall leider nicht die Lösung. Ich habe diesen Testfall geschrieben, weil ich sehr komplizierte Tests habe und in einigen Fällen habe ich festgestellt, dass Tests hängen bleiben, das bedeutet, dass für eine Weile nichts passiert. Meine Absicht ist es, jedes Mal einen neuen Timeout-Thread zu starten, wenn der Test abgeschlossen ist, wird dieser Thread zerstört, aber wenn das Thread-Timeout abgelaufen ist, sollte dieser Test fehlschlagen und andere Tests laufen lassen (ich habe ein paar 100's). ..).Ihre Lösung erfordert, dass ich alle meine Tests modifiziere und nicht funktionieren werde, da ich die Ausführung meiner Testmethode nicht blockieren kann – Tzahi

+0

Siehe aktualisierte Antwort – sll

+0

Diese Lösung erfordert, dass ich viel Code in meinen Tests schreibe, dies ist genau der Grund, warum ich Ich wollte Thread verwenden, der von der Klasseninitiierung gestartet wird und nicht die Testmethode. Dies erfordert auch, dass ich 2 Methoden für jeden Test schreibe - 1 für den Verzögerungsteil, so dass ich es auf dem Testmanager sehe und einen anderen zur Implementierung (anstatt anonymen Code zu schreiben) – Tzahi

Verwandte Themen