在我的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。不知怎的,我只是想退出我开始的程序而不影响它运行的VM。这不可能吗?
在玩了几个小时的代码之后,我意外地发现Robot
使用的WindowFinder
类有一个cleanUp
方法:“清理任何代码使用此机器人使用的资源(键盘,鼠标,打开窗口和{@link ScreenLock}
)。“。我尝试使用此而不是frame.close()
,结果证明它有效!它甚至不需要自定义SecurityManager
。
问题似乎是BasicRobot.robotWithCurrentAwtHierarchy()
调用在屏幕上获取锁定,而不是由frame.close()
释放。因此,当在第二个场景/测试中进行下一次BasicRobot.robotWithCurrentAwtHierarchy()
调用时,调用将阻止等待锁被释放,并有效地创建死锁。解决方案是使用robot.cleanUp
手动释放锁(它还会关闭并处置任何打开的窗口)。但是,为什么frame.close
在关闭最后一帧时不执行此操作超出了我的范围。
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();
}
}
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();
}
}
答案 0 :(得分:1)
这只是一个猜测:你必须在启动线程之前安装NoExitSecurityManagerInstaller。见http://docs.codehaus.org/display/FEST/Handling+System.exit