2013-08-25 10 views
17

Chcę utworzyć podstawowy test JUnit dla aplikacji JavaFX 8. Mam ten prosty przykładowy kod:Podstawowy test JUnit dla JavaFX 8

public class Main extends Application { 
    public static void main(String[] args) { 
     Application.launch(args); 
    } 
    @Override 
    public void start(Stage primaryStage) { 
     primaryStage.setTitle("Tabs"); 
     Group root = new Group(); 
     Scene scene = new Scene(root, 400, 250, Color.WHITE); 
     TabPane tabPane = new TabPane(); 
     BorderPane borderPane = new BorderPane(); 
     for (int i = 0; i < 5; i++) { 
      Tab tab = new Tab(); 
      tab.setText("Tab" + i); 
      HBox hbox = new HBox(); 
      hbox.getChildren().add(new Label("Tab" + i)); 
      hbox.setAlignment(Pos.CENTER); 
      tab.setContent(hbox); 
      tabPane.getTabs().add(tab); 
     } 
     // bind to take available space 
     borderPane.prefHeightProperty().bind(scene.heightProperty()); 
     borderPane.prefWidthProperty().bind(scene.widthProperty()); 

     borderPane.setCenter(tabPane); 
     root.getChildren().add(borderPane); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 
} 

Mam tylko ten kod do tej pory:

import javafx.application.Application; 
import javafx.stage.Stage; 
import org.junit.BeforeClass; 

public class BasicStart extends Application { 

    @BeforeClass 
    public static void initJFX() { 
     Thread t = new Thread("JavaFX Init Thread") { 
      @Override 
      public void run() { 
       Application.launch(BasicStart.class, new String[0]); 
      } 
     }; 
     t.setDaemon(true); 
     t.start(); 
    } 

    @Override 
    public void start(Stage primaryStage) throws Exception { 
     // noop 
    } 
} 

możesz mi powiedzieć jak mogę utworzyć testu JUnit dla powyższego kodu?

+2

polecam korzystania JemmyFX - to zajmuje trochę czasu i wysiłku, aby skonfigurować i przyzwyczaić, ale jest bardzo silny. Prawdopodobnie poświęcisz dużo czasu i wysiłku na robienie czegoś nie tak dobrego, jeśli zaczniesz od zera. – assylias

Odpowiedz

3

Najprostszym aproach jest następujący:

import javafx.application.Platform; 
import javafx.embed.swing.JFXPanel; 
import javafx.stage.Stage; 

import org.junit.Test; 

public class BasicStart { 

    @Test 
    public void testA() throws InterruptedException { 
     Thread thread = new Thread(new Runnable() { 

      @Override 
      public void run() { 
       new JFXPanel(); // Initializes the JavaFx Platform 
       Platform.runLater(new Runnable() { 

        @Override 
        public void run() { 
         new Main().start(new Stage()); // Create and 
                 // initialize 
                 // your app. 

        } 
       }); 
      } 
     }); 
     thread.start();// Initialize the thread 
     Thread.sleep(10000); // Time to use the app, with out this, the thread 
           // will be killed before you can tell. 
    } 

} 

Nadzieję, że to pomaga!

+6

Chciałbym uniknąć Thread.sleep(), jeśli możesz. To nie jest wielka sprawa z kilkoma testami, ale naprawdę zwalnia, gdy masz setki testów. Sprawdź, czy możesz zamiast tego użyć jakiegoś zaczepu. –

+0

W obecnej wersji nie wydaje się, aby zgłosić nieudane potwierdzenie (wewnątrz 'run') za pomocą normalnych mechanizmów raportowania JUnit, ponieważ' Runnable' nie może propagować 'Exception'. –

26

Używam reguły Junit do uruchamiania testów jednostkowych w wątku JavaFX. Szczegóły są podane w this post. Po prostu skopiuj klasę z tego posta, a następnie dodaj to pole do testów jednostkowych.

@Rule public JavaFXThreadingRule javafxRule = new JavaFXThreadingRule(); 

Ten kod działa dla obu JavaFX JavaFX 2 i 8.

+1

Działa to całkiem nieźle, jednak uruchomienie testu w wątku oznacza, że ​​nie można sypiać ani czekać, a żaden kod korzystający z platformy platform.runLater nie może zostać przetestowany - chyba że można zaproponować obejście. – Adam

+0

@Adam Dlaczego nie będziesz mógł skorzystać z żadnych uśpień lub czekania? Zwykle nie zaleca się ich stosowania w testach jednostkowych, ale nie rozumiem, dlaczego nie byłbyś w stanie ich użyć, jeśli naprawdę potrzebujesz. Jeśli chcesz użyć platformy Platform.runLater(), możesz po prostu uruchomić główny wątek, w przeciwnym razie po co wywoływać funkcję Platform.runLater(), jeśli jesteś już w wątku javafx? –

+1

Aby próbować wyjaśnić lepiej ... Mówię tutaj o testach integracyjnych, a nie o testach jednostkowych, mimo że korzystam z JUnit. Jeśli wyświetlacz jest aktualizowany z innego wątku, powiedzmy, że jest klientem sieciowym, wówczas należy użyć Platform.runLater (runnable), jednak ta operacja nie zostanie wykonana, dopóki test (uruchomiony na wątku fx) nie zostanie zakończony i nie zwróci kontroli do głównego Wątek FX, który będzie obsługiwał następne zadanie w kolejce. – Adam

2

oparciu o Brian Blonski „s answer stworzyłem JUnit-Testrunner, który robi w zasadzie to samo, ale jest nieco prostsze w użyciu moim zdaniem . Używając go, nasz test będzie wyglądać następująco:

@RunWith(JfxTestRunner.class) 
public class MyUnitTest 
{ 
    @Test 
    public void testMyMethod() 
    { 
    //... 
    } 
} 
+1

Wygląda na to, że Twój link jest uszkodzony. Chciałbym zobaczyć TestRunnera! – MikaelF

+1

Naprawiłem link. Ale powinienem cię ostrzec; Znalazłem kod, aby nie był bezpieczny dla wątków. –