When executing UI tests, such as SWTBot tests, when a test fails some popups might stay open and cause subsequent tests to fail. Even worse, the whole test suite execution can take longer than usual because all the following tests might fail after waiting for a timeout (of 5 seconds by default). It will also kill the visibility of the scope of impacted components.
In order to avoid this quirk, we are using a custom TestSuite to register a custom *JUnit Runlistener *on the RunNotifier. After all these abstracts words, let’s see in details how to implement it.
Register the listener
You have to extend the Suite class and then to register the listener on the RunNotifier.
public class CloseShellSuite extends Suite {@Override
public void run(final RunNotifier runNotifier) {
final RunListener listener = CleanShellListener.getInstance();
runNotifier.removeListener(listener);
runNotifier.addListener(listener);
super.run(runNotifier);
}
protected CloseShellSuite(final Class<?> klass, final Class<?>[] suiteClasses) throws InitializationError {
super(klass, suiteClasses);
}
Implement the RunListener
You need to override the testFinished method. Inside this method, you can access the SWTWorkbenchBot to be able to close all open shells - taking care not to close the main Eclipse shell - and also close all editors in order to get back to a clean environment.
public class CleanShellListener extends RunListener {
@Override
public void testFinished(final Description description) throws Exception {
final SWTWorkbenchBot bot = new SWTWorkbenchBot();
try {
closeAllShells(bot, description);
bot.saveAllEditors();
bot.closeAllEditors();
} catch (final Exception e) {
BonitaStudioLog.log("| Fails to clean shells after test : " + description.getMethodName());
BonitaStudioLog.log("|====================================================");
return;
}
}
private void closeAllShells(final SWTWorkbenchBot bot, final Description description) {
final SWTBotShell[] shells = bot.shells();
for (final SWTBotShell shell : shells) {
if (shell.isOpen() && !isEclipseShell(shell)) {
bot.captureScreenshot("screenshots/ShellOpenedAfter" + description.getMethodName() + ".jpg");
shell.close();
BonitaStudioLog.log("/!\\ Shell " + shell + " has been closed automatically,"
+ "please fix the corresponding test (" + description.getMethodName() + ")"
+ " to close it in @After (see screenshots)");
}
}
}
@SuppressWarnings("boxing")
public static boolean isEclipseShell(final SWTBotShell shell) {
return UIThreadRunnable.syncExec(new BoolResult() {
public Boolean run() {
return PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getShell() == shell.widget;
}
});
}
private static CleanShellListener INSTANCE = null;
private CleanShellListener() {
};
public static CleanShellListener getInstance() {
if (INSTANCE == null) {
synchronized (CleanShellListener.class) {
if (INSTANCE == null) {
INSTANCE = new CleanShellListener();
}
}
}
return INSTANCE;
}
Notice that we take a screenshot in the case of a remaining window. This is a big help for debugging.
This article is based on a simplified overview of code used at Bonitasoft. You can have a closer look on our Github repository.