FEST: запуск / остановка внешней SWING-программы, которая использует System.exit() без влияния на виртуальную машину
В моих сценариях Cucumber-jvm мне нужно запускать внешнюю jar-программу перед каждым сценарием, взаимодействовать с ней с помощью библиотеки FEST на всех этапах и, наконец, завершать работу программы, чтобы очистить планшет для следующего сценария. Мне нужна конкретная внешняя программа System.exit()
выйти, когда закрыто. В свою очередь, я не могу просто выйти из программы в моих тестах, так как это приведет к завершению всей виртуальной машины. Вместо этого я использую собственный SecurityManager, встроенный в FEST, чтобы переопределить 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 для завершения всей виртуальной машины. Каким-то образом я просто хочу выйти из программы, которую я запустил, не затрагивая виртуальную машину, в которой она запущена. Это не возможно?
Обновление - Решение найдено!
Поработав с кодом в течение нескольких часов, я случайно обнаружил, что Robot
класс, используемый WindowFinder
имеет cleanUp
метод, который: "очищает любые используемые ресурсы (клавиатура, мышь, открытые окна и {@link ScreenLock}
) используется этим роботом. ". Я пытался использовать это вместо frame.close()
и оказывается, это работает! Это даже не нужно обычай 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();
}
}
1 ответ
Это всего лишь предположение: вы должны установить NoExitSecurityManagerInstaller, прежде чем начинать свою ветку. См. http://docs.codehaus.org/display/FEST/Handling+System.exit