2017-10-16 59 views
2

我想測試具有JavaFX場景元素(如TextField或DatePicker)的方法。我在這裏找到How do you unit test a JavaFX controller with JUnit如何運行JavaFX應用程序的測試,如果我只有一個線程初始化的測試類,它對我來說工作正常。但是如果我有兩節課呢?我無法使用啓動方法初始化相同的線程,因爲會引發異常。如果我不會在第二個測試類中創建線程,那麼還有另一個例外。您可以在下面找到測試類和堆棧跟蹤。我也在考慮使用@AfterClass註解方法停止此線程,然後再次在第二課中啓動它,但我認爲這不可能。有人可以幫助我嗎?JavaFX與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 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 

異常

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 

回答

2

創建一個類MockApp extends Application並有一個靜態方法init()。在該方法中,創建一個新的單線程,在該線程中用適當的警衛來調用JavaFX平臺啓動(基本上已經完成)。 guard(一個布爾標誌)保證該方法被調用一次。關鍵是線程永不終止,因此允許您在所有測試的生命週期中訪問JavaFX平臺。美中不足的是,你需要添加類似:

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

爲在您使用JavaFX的,因爲你不知道在哪個測試運行的順序每個測試類。

在練習here中可以看到該方法(稍有改動)。