2017-10-16 3 views
2

Je voudrais tester des méthodes qui ont des éléments de scène JavaFX comme TextField ou DatePicker. J'ai trouvé ici How do you unit test a JavaFX controller with JUnit comment exécuter le test pour l'application JavaFX et ça marche bien pour moi si je n'ai qu'une seule classe de test où le Thread est initialisé. Mais qu'en est-il si j'ai deux cours? Je ne suis pas en mesure d'initialiser le même thread avec la méthode de lancement car une exception sera levée. Si je ne crée pas de thread dans la deuxième classe de test, il existe également une autre exception. Vous trouverez ci-dessous des classes de test et une trace de pile. Je pensais aussi à arrêter ce thread dans la méthode avec l'annotation @AfterClass, puis à le redémarrer en deuxième classe, mais je ne pense pas que ce soit possible. Est-ce que quelqu'un peut m'aider?JavaFX avec Junit

FirstTestClass

@RunWith(PowerMockRunner.class) 
@PrepareForTest({TextField.class, DatePicker.class}) 
public class FirstTestClass { 

    @BeforeClass 
    public static void javaFXInitializer() throws SQLException, InterruptedException { 
     Thread thread = new Thread("JavaFX Init Thread") { 
      public void run() { 
       Application.launch(Main.class); 
      } 
     }; 
     thread.setDaemon(true); 
     thread.start(); 
     Thread.sleep(5000); 
    } 

    @Test 
    public void firstTest() { 
     TextField textFieldMock = mock(TextField.class); 
     DatePicker datePickerMock = mock(DatePicker.class); 
     TestClass objectUnderTest = new TestClass(); 

     when(textFieldMock.getText()).thenReturn("2000"); 
     when(datePickerMock.getValue()).thenReturn(LocalDate.of(1992,1,1)); 

     //rest of code to test 
    } 

} 

SecondTestClass

@RunWith(PowerMockRunner.class) 
    @PrepareForTest({TextField.class, DatePicker.class}) 
    public class SecondTestClass { 

     @BeforeClass 
     public static void javaFXInitializer() throws SQLException, InterruptedException { 
      Thread thread = new Thread("JavaFX Init Thread") { 
       public void run() { 
        Application.launch(Main.class); 
       } 
      }; 
      thread.setDaemon(true); 
      thread.start(); 
      Thread.sleep(5000); 
     } 

     @Test 
     public void firstTest() { 
      TextField textFieldMock = mock(TextField.class); 
      DatePicker datePickerMock = mock(DatePicker.class); 
      TestClass objectUnderTest = new TestClass(); 

      when(textFieldMock.getText()).thenReturn("5000"); 
      when(datePickerMock.getValue()).thenReturn(LocalDate.of(1990,1,1)); 

      //rest of code to test 
     } 

    } 

Exception quand je l'initialise fil dans deux classes

Exception in thread "JavaFX IncomeTest Init Thread" java.lang.RuntimeException: java.lang.UnsatisfiedLinkError: Native Library C:\Program Files\Java\jdk1.8.0_144\jre\bin\glass.dll already loaded in another classloader 
     at com.sun.javafx.tk.quantum.QuantumToolkit.startup(QuantumToolkit.java:267) 
     at com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:211) 
     at com.sun.javafx.application.LauncherImpl.startToolkit(LauncherImpl.java:675) 
     at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:695) 
     at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$155(LauncherImpl.java:182) 
     at java.lang.Thread.run(Thread.java:748) 
Caused by: java.lang.UnsatisfiedLinkError: Native Library C:\Program Files\Java\jdk1.8.0_144\jre\bin\glass.dll already loaded in another classloader 
     at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1907) 
     at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1824) 
     at java.lang.Runtime.load0(Runtime.java:809) 
     at java.lang.System.load(System.java:1086) 
     at com.sun.glass.utils.NativeLibLoader.loadLibraryFullPath(NativeLibLoader.java:201) 
     at com.sun.glass.utils.NativeLibLoader.loadLibraryInternal(NativeLibLoader.java:94) 
     at com.sun.glass.utils.NativeLibLoader.loadLibrary(NativeLibLoader.java:39) 
     at com.sun.glass.ui.Application.loadNativeLibrary(Application.java:112) 
     at com.sun.glass.ui.Application.loadNativeLibrary(Application.java:120) 
     at com.sun.glass.ui.win.WinApplication.access$300(WinApplication.java:39) 
     at com.sun.glass.ui.win.WinApplication$1.run(WinApplication.java:118) 
     at com.sun.glass.ui.win.WinApplication$1.run(WinApplication.java:91) 
     at java.security.AccessController.doPrivileged(Native Method) 
     at com.sun.glass.ui.win.WinApplication.<clinit>(WinApplication.java:91) 
     at com.sun.glass.ui.win.WinPlatformFactory.createApplication(WinPlatformFactory.java:39) 
     at com.sun.glass.ui.win.WinPlatformFactory.createApplication(WinPlatformFactory.java:36) 
     at com.sun.glass.ui.Application.run(Application.java:146) 
     at com.sun.javafx.tk.quantum.QuantumToolkit.startup(QuantumToolkit.java:257) 
     ... 5 more 

Exception lorsque le fil est initialisé uniquement dans la première classe

java.lang.ExceptionInInitializerError 
     at sun.reflect.GeneratedSerializationConstructorAccessor12.newInstance(Unknown Source) 
     at java.lang.reflect.Constructor.newInstance(Constructor.java:423) 
     at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:45) 
     at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73) 
     at org.mockito.internal.creation.instance.ObjenesisInstantiator.newInstance(ObjenesisInstantiator.java:14) 
     at org.powermock.api.mockito.repackaged.ClassImposterizer.createProxy(ClassImposterizer.java:149) 
     at org.powermock.api.mockito.repackaged.ClassImposterizer.imposterise(ClassImposterizer.java:64) 
     at org.powermock.api.mockito.internal.mockcreation.DefaultMockCreator.createMethodInvocationControl(DefaultMockCreator.java:121) 
     at org.powermock.api.mockito.internal.mockcreation.DefaultMockCreator.createMock(DefaultMockCreator.java:69) 
     at org.powermock.api.mockito.internal.mockcreation.DefaultMockCreator.mock(DefaultMockCreator.java:46) 
     at org.powermock.api.mockito.PowerMockito.mock(PowerMockito.java:141) 
     at 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
     at java.lang.reflect.Method.invoke(Method.java:498) 
     at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68) 
     at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:326) 
     at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:89) 
     at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:97) 
     at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:310) 
     at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:131) 
     at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.access$100(PowerMockJUnit47RunnerDelegateImpl.java:59) 
     at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner$TestExecutorStatement.evaluate(PowerMockJUnit47RunnerDelegateImpl.java:147) 
     at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.evaluateStatement(PowerMockJUnit47RunnerDelegateImpl.java:107) 
     at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82) 
     at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:298) 
     at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87) 
     at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50) 
     at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:218) 
     at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:160) 
     at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:134) 
     at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34) 
     at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44) 
     at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:136) 
     at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:121) 
     at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:57) 
     at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59) 
     at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252) 
     at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141) 
     at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112) 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
     at java.lang.reflect.Method.invoke(Method.java:498) 
     at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189) 
     at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165) 
     at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85) 
     at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115) 
     at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75) 
Caused by: java.lang.IllegalStateException: Toolkit not initialized 
     at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:273) 
     at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:268) 
     at com.sun.javafx.application.PlatformImpl.setPlatformUserAgentStylesheet(PlatformImpl.java:550) 
     at com.sun.javafx.application.PlatformImpl.setDefaultPlatformUserAgentStylesheet(PlatformImpl.java:512) 
     at javafx.scene.control.Control.<clinit>(Control.java:87) 
     ... 50 more 

Répondre

2

Créer une classe MockApp extends Application et avoir une méthode statique init(). Dans cette méthode créer un nouveau thread unique dans lequel appeler le début de la plate-forme JavaFX (essentiellement ce que vous avez déjà fait) avec un garde approprié. Le garde (un drapeau booléen) garantit que la méthode est appelée au maximum une fois. Le point est que le thread ne se termine jamais, vous permettant ainsi d'accéder à la plate-forme JavaFX pendant la durée de tous vos tests. Le hic est que vous devez ajouter quelque chose comme:

@BeforeClass 
public void init() { 
    MockApp.init(); 
} 

pour chaque classe de test où vous utilisez JavaFX puisque vous ne connaissez pas l'ordre dans lequel des tests.

L'approche (avec des changements mineurs) peut être vu dans la pratique here.