I’m trying to wrap my head around Arquillian and perhaps even start using it in my project. I have a simple Java web app that deploys as a WAR to Tomcat.
In my project, I define a ServletContextListener impl so that I can execute code when Tomcat starts and stops the application.
I’m trying to write a super-simple Arquillian test class that uses ShrinkWrap and:
- Confirms that my bundled WAR can be deployed to Tomcat and started without throwing exceptions; and
- Can access a simple system property once the app is running (that the
ServletContextListenerchecks for); and - Confirms that when Tomcat shuts down, no exceptions are thrown (clean shutdown)
Also, my class that implements ServletContextListener is called AppLifecycleManager:
public class AppLifeCycleManager implements ServletContextListener {
private String logLevel;
// Injected by Guice, but that's not really relevant for this question.
@Inject
private Logger logger;
// Getter and setter for logLevel and logger
@Override
public void contextInitialized(ServletContextEvent event) {
logLevel = System.getProperty("log.level");
}
@Override
public void contextDestroyed(ServletContextEvent event) {
logger.info("Peacefully shutting down the application.");
}
}
So far, here’s my best attempt:
@RunWith(Arquillian.class)
public class MyFirstRealIntegrationTest {
@Deployment
public static Archive<?> createDeployment() {
// Haven't figured this part out yet, but for the sake of
// this question lets pretend this returns a properly-packaged
// WAR of my web app, the same that my Ant build currently produces.
}
@Test
public void shouldBeAbleToStartTomcatWithoutExceptions() {
// Given
Archive war = createDeployment();
// When - deploy war to Tomcat container
try {
// ??? how to access/init a Tomcat container?
TomcatContainer tomcat = new TomcatContainer(); // this is wrong
tomcat.start();
} catch(Throwable throwable) {
// Starting the container should not throw exceptions
Assert.fail();
}
}
@Test
public void shouldBeAbleToStopTomcatWithoutExceptions {
// Same setup as above test but stops tomcat and checks for
// thrown exceptions. Omitted for brevity.
}
@Test
public void shouldHaveAccessToSysPropsOnceRunning() {
// Here, deploy to the container and start it.
// Then, confirm that AppLifecycleManager correctly read
// the log.level system property.
// Given
Archive war = createDeployment();
TomcatContainer tomcat = new TomcatContainer();
// When - AppLifeycleManager should now read the system property
tomcat.start();
// Then - make sure log.level was set to "DEBUG" and that it was
// correctly read by AppLifeCycleManager.
Assert.assertTrue(war.getClass(AppLifeCycleManager.class)
.getLogLevel().equals("DEBUG"));
}
}
So, given my approach here, I immediately have several problems:
- I’m not sure how to access/instantiate my Tomcat container so that it can even be started/stopped
- I’m not sure how to actually execute tests from inside my running/deployed web app. In the 3rd test above I used
war.getClass(AppLifeCycleManager.class).getLogLevel()to try and get access to a “live” class instance and check itslogLevelproperty’s runtime value, but I know this is wrong.
So I ask: how would a battle-worn Arquillian veteran write these 3 simple tests, and how do I actually go about performing tests on my “running” web app from inside the JUnit test? Thanks in advance.
You’re almost there.
createDeploymentmanages the lifecycle of your embedded container for you (starts and stops the virtual container automatically). That way, you’re just focussing on the tests themselves. To write your integration tests, there’s no “framework” or “Arquillian API” to code against. You just call classes and methods the way your main code does.The key thing here is: your tests are actually running inside the container. If an exception occurs, or if your assert fails, the Arquillian runner throws an exception and stops the container. For your code example, where you’re testing to see if you can read a system property:
Remember,
Assert.assertTrue(System.getProperty("log.level") != null)Arquillian is “transporting” your code inside the container you configure it for. So that assert is actually running inside your deployed container.