2016-01-29 9 views
10

Ich versuche, eine Methode zu testen, die es Arbeit in einem separaten Thread der Fall ist, vereinfacht es so ist:Wie man auf einen Thread wartet, der seinen eigenen Thread hervorbringt?

public void methodToTest() 
{ 
    Thread thread = new Thread() 
    { 
     @Override 
     public void run() { 
      Clazz.i = 2; 
     } 
    }; 
    thread.start(); 
} 

In meinem Gerät zu testen möchte ich, dass 2 == Clazz.i testen, aber ich kann tue dies, weil ich denke, dass die Assert ausgeführt wird, bevor der Thread den Wert ändert. Ich dachte daran, einen anderen Thread zu verwenden, um es zu testen und dann mit Join zu warten, aber es funktioniert immer noch nicht.

SSCCE:

@Test 
public void sscce() throws InterruptedException 
{ 
    Thread thread = new Thread() 
    { 
     @Override 
     public void run() { 
      methodToTest() 
     } 
    }; 
    thread.start();  
    thread.join(); 
    AssertEquals(2, Clazz.i); 
} 

public static class Clazz 
{ 
    public static int i = 0; 
} 

Ich denke, das liegt daran, dass der Test Haupt-Code, um einen Thread erstellt, die (verbunden) mit dem zweiten Thread warten, aber der zweite Thread die Arbeit nicht tun, schafft es eine andere Thread, um die Arbeit zu tun und dann beendet, die den ersten Thread fortsetzt, während der dritte Thread die Clazz.i = 2 nach der Assertion macht.

Wie kann ich es so machen, dass der erste Thread wartet auf den Thread, der sowie alle Threads gestartet wird, die dieser Thread startet?

+1

Fügen Sie join() im Haupt-Thread und im zweiten Thread hinzu –

+1

@ravindra Ich habe einen Join im ersten Thread mit dem 2. Thread, direkt über dem assertEquals – Aequitas

+1

http://Stackoverflow.com/questions/631598/how-to- use-junit-to-test-asynchrone-Prozesse? – Gavriel

Antwort

5

Ohne einen Verweis auf den Thread erstellt in methodToTest, können Sie nicht, ganz einfach. Java bietet keinen Mechanismus zum Auffinden von "Threads, die während dieses bestimmten Zeitraums erzeugt wurden" (und selbst wenn dies der Fall wäre, wäre es wohl ein hässlicher Mechanismus zu verwenden).

Wie ich es sehe, haben Sie zwei Möglichkeiten:

  • Make methodToTest Warten auf den Faden es laicht. Wenn Sie explizit möchten, dass dies eine asynchrone Aktion ist, können Sie das natürlich nicht gut machen.
  • Geben Sie den neu erstellten Thread von methodToTest zurück, so dass alle Anrufer auf sie warten können, wenn sie dies wünschen.

Es kann angemerkt werden, dass die zweite Wahl auf ein paar verschiedene Arten formuliert werden kann. Sie könnten zum Beispiel ein abstraktes Future -ähnliches Objekt anstelle eines Threads zurückgeben, wenn Sie die Freiheit von methodToTest erweitern möchten, um verschiedene Arten der asynchronen Arbeit zu verwenden. Sie könnten vielleicht auch einen globalen Task-Pool definieren, bei dem Sie alle asynchronen Aufgaben erzwingen, damit er ausgeführt wird, und dann warten, bis alle Aufgaben im Pool abgeschlossen sind, bevor Sie die Assertion überprüfen. Solch ein Aufgabenpool könnte die Form einer ExecutorService oder einer ThreadGroup oder irgendeiner Anzahl anderer Formen annehmen. Sie alle tun das gleiche am Ende, aber möglicherweise mehr oder weniger für Ihre Umgebung geeignet - der wichtigste Punkt ist, dass Sie explizit geben Sie den Aufrufer Zugriff auf den neu erstellten Thread, ist auf die eine oder andere Weise.

+0

Ich kann nicht die erste aus dem Grund, die Sie sagen, und ich kann nicht die 2. aus zwei Gründen tun, eine sollte ich nicht den tatsächlichen Code ändern, nur testen, und zwei, wenn ich es geändert, um einen Thread zurückzugeben Ich müsste die anderen tausend Implementierungen dieser abstrakten Methode ändern, was eine viel zu große Veränderung ist. Vielen Dank für Ihren Hinweis, aber – Aequitas

+0

@Aequitas: Vielleicht möchten Sie die letzte Option, die ich gerade bearbeitet habe, dann überprüfen. – Dolda2000

+0

Könnten Sie mir ein Beispiel geben, wie ich das machen würde? Ich schaue nach vorne, aber verstehe es nicht wirklich. Wäre das alles auch in der Testklasse? – Aequitas

3

Da Ihre Threads unterschiedliche Operationen auszuführen scheinen, können Sie CountDownLatch verwenden, um Ihr Problem zu lösen.

Deklarieren Sie einen CountDownLatch im Haupt-Thread und übergeben Sie dieses Latch-Objekt an andere Threads. Verwenden Sie im Hauptthread awarts() und dekrementieren Sie den Latch in anderen Threads.

In Hauptthread: (erster Thread)

CountDownLatch latch = new CountDownLatch(2); 
/* Create Second thread and pass the latch. Pass the same latch from second 
    thread to third thread when you are creating third thread */ 
try { 
    latch.await(); 
} catch (InterruptedException e) { 
    e.printStackTrace(); 
} 

Überschreiten diese Verriegelung zu zweiten und dritten Gewinden und verwendet Countdown in diesen Fäden

In zweiten und dritten Gewindegängen,

try { 
    // add your business logic i.e. run() method implementation 
    latch.countDown(); 
} catch (InterruptedException e) { 
    e.printStackTrace(); 
} 

Schauen Sie sich article zum besseren Verständnis an.

ExecutorServiceinvokeAll() API ist, andere bevorzugte Lösung.

0

Sie können nicht Unit-Test-Funktionen, die das Gerät nicht bieten.

Sie sagen, dass Sie, dass methodToTest()schließlich Sätze Clazz.i=2, um zu überprüfen, wollen aber was bedeutet „schließlich“ bedeuten? Ihre methodToTest() Funktion bietet ihrem Anrufer keine Möglichkeit zu wissen, wann Clazz.i festgelegt wurde. Der Grund, warum Sie eine harte Zeit haben, herauszufinden, wie die Funktion zu testen ist, weil Ihr Modul nicht bieten diese Funktion.

Dies könnte eine gute Zeit für Sie auf Test Driven Development zu lesen (TDD). Dort schreiben Sie zuerst die Tests und dann schreiben Sie Code, der die Tests bestanden hat. Das Schreiben der Tests hilft Ihnen, ein klareres Bild von dem zu zeichnen, was das Modul machen soll.

Es hat auch einen Nebeneffekt: Wenn Sie strenge TDD Praxis (das heißt, wenn Sie nie Modul Code außer schreiben, um einen Testdurchlauf zu machen), dann Ihre Testabdeckung wird zu 100% betragen.

Und das führt zu einem weiteren Nebeneffekt: Wenn Sie 100% Testabdeckung haben, dann können Sie ohne Angst umgestalten, denn wenn Sie irgendetwas kaputt machen, werden Sie das in Ihren Unit Tests sehen.

Verwandte Themen