【问题标题】:Stop JUnit from finishing until all other threads have been stopped停止 JUnit 完成,直到所有其他线程都停止
【发布时间】:2015-07-04 19:16:13
【问题描述】:

在我的单元测试期间,我想使用 Java FX 绘制一些图形。现在的问题是,一旦单元测试完成,JVM 和 Java FX 就会关闭,我无法检查生成的图(与刚从 main 方法启动“测试”的情况不同) .所以我的问题是,有没有办法在特定线程完成之前阻止 JUnit 退出,即直接从 main 方法开始测试时复制行为?是的,我知道绘图很可能不是通常应该在单元测试期间完成的事情。 目前我正在做这样的事情:

//@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();
}

【问题讨论】:

  • 下面提到的 CountDownLatch 方法很好,但是您的测试似乎没有执行任何验证/断言,这意味着只有两个结果是成功或抛出异常。

标签: java multithreading junit javafx


【解决方案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,对于我从您更新的描述中读到的内容,它最合适。

【讨论】:

  • 这需要在您的主代码中添加测试元素(一个 cdl)吗?
  • @RaGe 是的,确实如此。因为JavaFX的主Stage不能以阻塞的方式显示。阻塞必须以相反的方式完成,这可以使用CountDownLatch 轻松完成。
  • 将代码添加到您的主代码库中,除了启用特定的测试用例之外没有任何功能,这对我来说听起来像是不好的做法。我更喜欢 OP 的 thread.join() 方式。
  • 感谢所有反馈。我编辑了这个问题,以使我的意图更清楚。基本上我想摆脱所有显式线程代码,如果直接从 main 运行相同的代码(即如果“测试”是从 main 运行,我不必显式地等待),则这些代码是不必要的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多