• Have you ever wanted to test a web application using real HTTP requests, but still have the opportunity to verify server-side state and behavior?
  • Wouldn’t it be great to have the full power of Arquillian Drone, driving Selenium or WebDriver on the client, then combine that with an Arquillian in-container test?

Now you can!

Ike’s innovative army has created yet another powerful weapon for your testing arsenal, Arquillian Warp.

Testing on both sides of the request

Arquillian Warp fills the void between client-side and server-side testing. Using Warp, you can initiate an HTTP request using a client-side testing tool such as WebDriver and, in the same request cycle, execute in-container server-side tests. This powerful combination lets you cover integration across client and server.

Now you can send real requests that execute real application logic and render content in a real browser and test it end-to-end. Mocks? Who needs those? Imagine the debugging possibilities this opens up!

This may sound like sci-fi, but it’s a reality. It’s advanced alien technology for killing real bugs that you can get your hands on today!

Let’s warp to the code

We’ll start with a normal Arquillian Drone client-side test with one enhancement, a @WarpTest annotation on the test class. This extra annotation instructs Arquillian Warp to enhance the request.

@WarpTest
@RunWith(Arquillian.class)
public class BasicWarpTest {
    @Drone
    WebDriver browser;

    @ArquillianResource
    URL contextPath;

    @Deployment
    public static WebArchive createDeployment() { ... }

    @Test
    @RunAsClient
    public void test_initial_page() {
        // triggers a HTTP request to a server
        browser.navigate().to(contextPath);
        // stay tuned...
    }
}

Note that you can use any HTTP client. For the sake of simplicity we’ve used @Drone to hook WebDriver (Selenium 2) into our test. Additionally, we’ve declared a web archive to be tested and injected its URL into the test case.

So far, we’ve defined a basic Drone test. Let’s start to warp this test so we can use it to test server-side logic as well. We begin by defining an implementation of ServerAssertion as an inner class of the test:

public static class InitialRequestAssertion extends ServerAssertion {
    @Inject
    TowelBean towel;

    @AfterPhase(RENDER_RESPONSE)
    public void test_initial_state() {
        // verify we are on right viewId
        assertEquals("/index.xhtml", FacesContext.getCurrentInstance().getViewRoot().getViewId());

        // assert the bean state
        assertNull(42, towelBean.getAnswerToLife());
    }
}

An object of this assertion class will be later enriched on the server (i.e., TowelBean will be injected) and then the lifecycle method annotated with @AfterPhase will be invoked in an appropriate phase of the request (after the response is rendered in the JSF lifecycle). This lifecycle method is effectively our server-side test.

All we need to do now is hook this assertion class to the request that is initiated by the browser. To do that, we warp the Selenium call in a Warp action:

@Test
@RunAsClient
public void test_initial_page() {
    // define the client action which will lead to HTTP request
    Warp.execute(new ClientAction() {
        public void action() {
            // the original request
            browser.navigate().to(contextPath);
        }
    
    // enhance the subsequent HTTP request with ServerAssertion
    }).verify(new InitialRequestAssertion());
}

That’s it! Here’s how it plays out:

  1. The Selenium-controlled browser initiates an HTTP request
  2. The request is trapped and enhanced with the InitialRequestAssertion object (which gets added as a payload of the request)
  3. When the request arrives at the server, the InitialRequestAssertion assertion object is registered with Arquillian and the request lifecycle proceeds
  4. After the response is rendered on the server, the InitialRequestAssertion object is enriched with all the required resources (EJB beans, CDI beans, Spring beans or Arquillian resources) and the lifecycle (test) method is invoked
  5. Once the request is complete, the InitialRequestAssertion object is sent back to the client
  6. If anything on the server-side failed (including assertions you defined), the failure is propagated back to the client and handled as a test failure

Currently, Warp supports lifecycle callbacks for the Servlet and JSF lifecycles, but it’s designed to be able to handle any server-side lifecycle.

Some of the highlights in this release

Support for Servlet events

Warp gives you the ability to test any Servlet lifecycle with these two lifecycle annotations:

@BeforeServlet – triggered before the request is processed by the Servlet
@AfterServlet – triggered after the request is processed by the Servlet

Support for JSF lifecycle events (Phaser extension)

Warp’s Phaser extension provides integration with the JSF lifecycle. You can use these lifecycle annotations to test the application in any JSF phase:

@BeforePhase(Phase) – triggered before the given JSF phase is executed
@AfterPhase(Phase) – triggered after the given JSF phase is executed

Compatible with any HTTP client

Warp works with any HTTP client: Selenium, HtmlUnit, HttpUnit, REST client, JavaScript test, Android device. No boundaries here!

Open to more protocols

Only the HTTP protocol is supported currently, but other protocols can be supported as well! (An SPI will be defined in a later releases)

Open to more frameworks

Warp is designed to support any server-side web framework based on the Servlets API

Need to know more?

You can find the complete Maven-based sample usage in the Arquillian Showcase.

Additionally, you can look at the functional tests in the Warp test suite:

Roadmap

In future releases, we’ll be looking into further improving the extension, most notably by providing framework-specific enrichments:

  • Injectable HttpServletRequest
  • Injectable FacesContext
  • etc.

Warp offers many possibilities for integration:

  • Support for wide range of server-side web frameworks (Wicket, Vaadin, GWT, Tapestry, …)
  • Support for alternative protocols (WebSockets)
  • Built-in support for variety of client-side testing tools

Call to action

If you would like to have support for your favorite web framework, you see features that are missing or you can see room for improvement, don’t hesitate and come to the “Arquillian forums”: or the # channel on Freenode IRC!

We would love to hear your ideas and feedback for how to stretch Warp to reach beyond the boundaries of the test galaxy!


blog comments powered by Disqus