4

在我的 Cucumber-jvm 场景中,我需要在每个场景之前运行一个外部 jar 程序,在步骤中使用 FEST 库与其交互,最后关闭程序以清理下一个场景的板岩。我需要System.exit()在关闭时退出的特定外部程序。反过来,我不能在我的测试中退出程序,因为这会终止整个 VM。相反,我使用 FEST 中内置的自定义 SecurityManager 来覆盖System.exit()调用。但是,我无法让它正常工作。

下面示例 1中的代码尝试在 Cucumber@Before挂钩中启动外部程序并在挂钩中将其关闭@After。当我运行时,它只适用于一种情况mvn verify。但是,对于两个或更多场景,maven 只是挂在行上:

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running test.acceptance.CucumberRunner 

之后什么也没有发生。我可以看到外部程序启动并关闭了一次,但第二次启动它并没有关闭。当我手动关闭它时,maven 输出以下内容:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-failsafe-
plugin:2.16:integration-test (default) on project acceptance-tests: Execution default of
goal org.apache.maven.plugins:maven-failsafe-plugin:2.16:integration-test failed: The
forked VM terminated without saying properly goodbye. VM crash or System.exit called ?

有谁知道这里发生了什么?似乎问题在于外部程序根本没有终止 - 可能是NoExitSecurityManagerInstaller我正在使用的错误。但是,我不知道如何防止对 System.exit 的调用终止整个 VM。不知何故,我只想退出我启动的程序,而不影响它正在运行的虚拟机。那不可能吗?

更新 - 找到解决方案!

在玩了几个小时的代码后,我无意中发现使用的RobotWindowFinder有一个cleanUp方法:“清理{@link ScreenLock}这个机器人使用的所有使用的资源(键盘、鼠标、打开的窗口和)。” . 我尝试使用它而不是frame.close()它,结果证明它有效!它甚至不需要 custom SecurityManager

问题似乎是该BasicRobot.robotWithCurrentAwtHierarchy()调用在屏幕上获得了一个锁定,该锁定不是由frame.close(). 因此,当BasicRobot.robotWithCurrentAwtHierarchy()在第二个场景/测试中进行下一次调用时,调用将阻塞等待锁被释放,并有效地创建死锁。解决方案是使用手动释放锁robot.cleanUp(这也会关闭并处理任何打开的窗口)。但是,当它关闭最后一帧时为什么frame.close不这样做超出了我的范围。

示例 1

public class CucumberHooks {
    private FrameFixture frame;

    @Before
    public void setup() throws InterruptedException, IOException {
        Thread t = new Thread(new Runnable() {
            public void run() {
                File file = new File(System.getProperty("external-jar"));
                URLClassLoader cl = null;
                try {
                    cl = new URLClassLoader( new URL[]{file.toURI().toURL()} );
                }
                catch (MalformedURLException e) {}

                Class<?> clazz = null;
                try {
                    clazz = cl.loadClass("MainClass");
                }
                catch (ClassNotFoundException e) {}

                Method main = null;
                try {
                    main = clazz.getMethod("main", String[].class);
                }
                catch (NoSuchMethodException e) {}

                try {
                    main.invoke(null, new Object[]{new String[]{}});
                }
                catch (Exception e) {}
            }
        });
        t.start();

        GenericTypeMatcher<JFrame> matcher = new GenericTypeMatcher<JFrame>(JFrame.class) {
            protected boolean isMatching(JFrame frame) {
                return "External Jar Title".equals(frame.getTitle()) && frame.isShowing();
            }
        };

        frame = WindowFinder.findFrame(matcher).using(BasicRobot.robotWithCurrentAwtHierarchy());
    }

    @After
    public void shutDown() throws InterruptedException {
        NoExitSecurityManagerInstaller i = NoExitSecurityManagerInstaller.installNoExitSecurityManager();
        frame.close();
        i.uninstall();
    }
}

示例 2

public class CucumberHooks {
    private FrameFixture frame;
    private Robot robot;

    @Before
    public void setup() throws InterruptedException, IOException {
        Thread t = new Thread(new Runnable() {
            public void run() {
                File file = new File(System.getProperty("external-jar"));
                URLClassLoader cl = null;
                try {
                    cl = new URLClassLoader( new URL[]{file.toURI().toURL()} );
                }
                catch (MalformedURLException e) {}

                Class<?> clazz = null;
                try {
                    clazz = cl.loadClass("MainClass");
                }
                catch (ClassNotFoundException e) {}

                Method main = null;
                try {
                    main = clazz.getMethod("main", String[].class);
                }
                catch (NoSuchMethodException e) {}

                try {
                    main.invoke(null, new Object[]{new String[]{}});
                }
                catch (Exception e) {}
            }
        });
        t.start();

        GenericTypeMatcher<JFrame> matcher = new GenericTypeMatcher<JFrame>(JFrame.class) {
            protected boolean isMatching(JFrame frame) {
                return "External Jar Title".equals(frame.getTitle()) && frame.isShowing();
            }
        };

        robot = BasicRobot.robotWithCurrentAwtHierarchy();
        frame = WindowFinder.findFrame(matcher).using(robot);
    }

    @After
    public void shutDown() {
        robot.cleanUp();
    }
}
4

1 回答 1

1

It's just a guess: you have to install the NoExitSecurityManagerInstaller before you start your thread. See http://docs.codehaus.org/display/FEST/Handling+System.exit

于 2014-01-21T16:30:07.040 回答