@Deployment(testable = true)
So far, we've focused on testing your application internals, but we also want to test how others (people, or other programs) interact with the application. Typically, you want to make sure that every use case and execution path is fully tested. Third parties can interact with your application in a number of ways, for example web services, remote EJBs or via http. You need to check that you object serialization or networking work for instance.
This is why Arquillian comes with two run modes, in container and as client. in container is to test your application internals and as client is to test how your application is used by clients. Lets dive a bit deeper into the differences between the run modes and see how they effect your test execution and packaging.
@Deployment(testable = true)
As we mentioned above, we need to repackage your @Deployment, adding some Arquillian support classes, to run in-container. This gives us the ability to communicate with the test, enrich the test and run the test remotely. In this mode, the test executes in the remote container; Arqullian uses this mode by default.
See the Complete Protocol Reference for an overview of the expected output of the packaging process when you provide a @Deployment.
@Deployment(testable = false)
Now this mode is the easy part. As opposed to in-container mode which repackages and overrides the test execution, the as-client mode does as little as possible. It does not repackage your @Deployment nor does it forward the test execution to a remote server. Your test case is running in your JVM as expected and you're free to test the container from the outside, as your clients see it. The only thing Arquillian does is to control the lifecycle of your @Deployment.
Here is an example calling a Servlet using the as client mode.
@RunWith(Arquillian.class) public class LocalRunServletTestCase { @Deployment(testable = false) public static WebArchive createDeployment() { return ShrinkWrap.create(WebArchive.class, "test.war") .addClass(TestServlet.class); } @Test public void shouldBeAbleToCallServlet(@ArquillianResource(TestServlet.class) URL baseUrl) throws Exception { // http://localhost:8080/test/ String body = readAllAndClose(new URL(baseUrl, "/Test").openStream()); Assert.assertEquals( "Verify that the servlet was deployed and returns the expected result", "hello", body); } }
@Deployment(testable = true) public static WebArchive create() { } @Test // runs in container public void shouldBeAbleToRunOnContainerSide() throws Exception { } @Test @RunAsClient // runs as client public void shouldBeAbleToRunOnClientSide() throws Exception { }
It is also possible to mix the two run modes within the same test class. If you have defined the Deployment to be testable, you can specify the @Test method to use run mode as client by using the @RunAsClient annotation. This will allow two method within the same test class to run in different modes. This can be useful if you in a run as client mode want to execute against a remote endpoint in your application, for then in the next test method assert on server side state the remote endpoint migh thave created.
The effect of the different run modes depend on the DeployableContainer used. Both modes might seem to behave the same in some Embedded containers, but you should avoid mixing your internal and external tests. One thing is that they should test different aspects of your application and different usecases, another is that you will miss the benefits of switching DeployableContainers and run the same tests suite against a remote server if you do.