2015-04-26 120 views
3

在我的單元測試期間,我想用Java FX繪製一些數字。現在的問題是,一旦單元測試完成,JVM和Java FX就會關閉,並且我無法檢查生成的繪圖(不像在「測試」剛剛從主要方法開始的情況下) 。所以我的問題是,是否有辦法在特定線程完成之前阻止JUnit退出,即直接從主方法開始測試時複製行爲?是的,我知道在一般的單元測試中,繪圖很可能不是真正應該完成的事情。 目前我在做這樣的事情:停止JUnit整理,直到所有其他線程都停止

//@ContextConfiguration(classes = {DummyConfig.class }) 
//@RunWith(SpringJUnit4ClassRunner.class) 
public class MainViewTest { 

    private boolean fromMain = false; 

    // starting the "test" from main does not require explicit waiting for 
    // for the JavaFX thread to finish .. I'd like to replicate this 
    // behaviour in JUnit (by configuring JUnit, not my test or application code) 
    public static void main(String [] args){ 
     new MainViewTest(true).test(); 
    } 

    public MainViewTest(){} 

    private MainViewTest(boolean fromMain){ 
     this.fromMain = fromMain; 
    } 

    @Test 
    public void test() { 

     //do some tests.... 

     //plot some results... 
     PlotStage.plotStage(new QPMApplication() { 
      @Override 
      public Stage createStage() { 
       Stage stage = new Stage(); 
       StackPane root = new StackPane(); 
       Scene scene = new Scene(root, 300, 300); 
       stage.setTitle("Stage"); 
       stage.setScene(scene); 
       stage.setOnCloseRequest(new EventHandler<WindowEvent>(){ 
        @Override 
        public void handle(WindowEvent event) { 
         Platform.exit(); 
        } 
       }); 
       return stage; 
      } 
     }); 

     System.out.println("Stage started"); 
     // how to get rid of this block (or using a countdownlatch) but 
     // still waiting for the threads to finish? 
     Set<Thread> threads = Thread.getAllStackTraces().keySet(); 
     if (!fromMain) { 
      System.out.println("checking threads..."); 
      for (Thread thread : threads) { 
       if (thread.getName().contains("JavaFX")) { 
        try { 
         thread.join(); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
      } 
     } 
    } 
} 

的問題是在這裏,我想擺脫這個討厭的塊要等到所有的JavaFX平臺明確退出。 我很欣賞關於使用倒數鎖存器而不是顯式加入Java FX線程的答案。但是,這仍然要求我明確地停止當前的線程。但是,我寧願以某種方式「告訴」JUnit等待JavaFX線程完成。

所以基本上我正在尋找的是一種告訴JUnit在我的測試方法中沒有任何阻塞代碼的情況下等待特定線程的方法。

附件:最小運行例子

public class PlotStage { 

    public static boolean toolkitInialized = false; 

    public static void plotStage(QPMApplication stageCreator) { 
     if (!toolkitInialized) { 
      Thread appThread = new Thread(new Runnable() { 
       @Override 
       public void run() { 
        Application.launch(InitApp.class); 
       } 
      }); 
      appThread.start(); 
     } 

     while (!toolkitInialized) { 
      try { 
       Thread.sleep(100); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
     Platform.runLater(new Runnable() { 
      @Override 
      public void run() { 
       Stage stage = stageCreator.createStage(); 
       stage.show(); 
      } 
     }); 
    } 

    public static class InitApp extends Application { 
     @Override 
     public void start(final Stage primaryStage) { 
      toolkitInialized = true; 
     } 
    } 
} 


public interface QPMApplication { 
    public abstract Stage createStage(); 
} 
+0

下面提到的CountDownLatch方法很好,但是您的測試似乎沒有執行任何驗證/斷言,這意味着只有兩個結果成功或拋出異常。 – Jonathan

回答

1

必要的類使用一個CountDownLatch

  1. 1初始化。
  2. Stage已關閉時,調用countDown()
  3. 在JUnit測試中,請致電await()等待Stage關閉。

例子:

CountDownLatch cdl = new CountDownLatch(1); 
// TODO show the stage and do not forget to add cdl.countDown() to your 
// stage.setOnCloseRequest 
cdl.await(); 

替代#1:

使用JavaFX Junit Rule直接在FX應用程序線程執行的所有操作。


替代#2:

使用TestFX,爲我從你更新的描述看,它最適合。

+0

這需要將測試元素(一個cdl)添加到您的主代碼? – RaGe

+0

@RaGe是的,它的確如此。因爲JavaFX的主'Stage'不能以阻塞的方式顯示。阻塞必須通過其他方式來完成,這可以使用'CountDownLatch'輕鬆完成。 – eckig

+2

將代碼添加到您的主代碼庫中,除了啓用特定的測試用例外,這些代碼沒有任何功能,這聽起來對我來說是不好的練習。我更喜歡OP的thread.join()方式。 – RaGe