2012-07-08 17 views
20

¿Cuál es la forma correcta de inicializar el tiempo de ejecución JavaFX para que pueda probar unidades (con JUnit) controladores que hacen uso de las facilidades de concurrencia y Platform.runLater(Runnable)?¿Cómo se prueba un controlador JavaFX con JUnit

Llamando Application.launch(...) del método @BeforeClass resulta en un bloqueo muerto. Si Application.launch(...) no se llama a continuación, el siguiente error se lanza:


java.lang.IllegalStateException: Toolkit not initialized 
    at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:121) 
    at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:116) 
    at javafx.application.Platform.runLater(Platform.java:52) 
    at javafx.concurrent.Task.runLater(Task.java:1042) 
    at javafx.concurrent.Task.updateMessage(Task.java:987) 
    at com.xyz.AudioSegmentExtractor.call(AudioSegmentExtractor.java:64) 
    at com.xyz.CompletionControllerTest.setUp(CompletionControllerTest.java:69) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:601) 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) 
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236) 
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) 
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) 

Seguimiento: este es el motivo que he estado usando basa en la recomendación por @SergeyGrinev.

... // Inside test class 

public static class AsNonApp extends Application { 
    @Override 
    public void start(Stage primaryStage) throws Exception { 
     // noop 
    } 
} 

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

Respuesta

14

Calling launch() de @BeforeClass es un enfoque correcto. Solo tenga en cuenta que launch() no devuelve el control al código de llamada. Entonces debes envolverlo en new Thread(...).start().

7

Me pareció que esto funciona, ... pero solo después de agregar un Thread.sleep (500) después de iniciar el hilo de la aplicación JavaFX. Es de suponer que se necesita algún tiempo para conseguir el ambiente FX y listo (alrededor de 200 ms en mi MacBook Pro retina)

@BeforeClass 
public static void setUpClass() throws InterruptedException { 
    // Initialise Java FX 

    System.out.printf("About to launch FX App\n"); 
    Thread t = new Thread("JavaFX Init Thread") { 
     public void run() { 
      Application.launch(AsNonApp.class, new String[0]); 
     } 
    }; 
    t.setDaemon(true); 
    t.start(); 
    System.out.printf("FX App thread started\n"); 
    Thread.sleep(500); 
} 
+3

[Application.launch] (No debe ser llamado más de una vez o se lanzará una excepción). La documentación indica: "No se debe invocar más de una vez o se lanzará una excepción", algo a tener en cuenta si intenta ejecutar el método setUpClass() en esta respuesta más de una vez. – jewelsea

Cuestiones relacionadas