Going Mobile with Arquillian
I have recently reviewed Arquillian‘s basic features and proof-tested it on a simple example. Today, I would like to talk about using Arquillian in a more realistic scenario. My ultimate goal is to tailor the tool for mobile apps development. For a start I sticked to a pure web and utilized jQuery Mobile. To give it a bit of a typical enterprise flavor I added JSF 2.0 and JBoss server to the mixture. I was curious how and whether the tool would be able to cope with advanced UI and other intricacies. Once again, an exciting experience in the end and a few thoughts to share..
The involved application is a news reader, not dissimilar to the one described at mobile tuts+. For the sake of a variety of technologies and tinier client code I implemented the actual reader as a JSF bean, Primo showed me the way.. Having a brand new shiny news reader in place I could not wait to start with writing automated integration tests.
Before I dig into details, I should say what has been achieved. The tests are triggered via a Maven command:
mvn clean verify
The rest is driven by Arquillian. First the application is deployed, then a browser is invoked and finally user actions are simulated by using Selenium. Screenshots are taken during the tests and they are available in the test build directory along with test reports. The application is automatically removed from the server as soon as the last test is over.
My first concern was deployment. As the app consisted of a number of different resources I was reluctant to opt for an exhaustive list:
.. // A decisive NO to this.. public static final String WEBAPP_SRC = "src/main/webapp"; .. @Deployment(testable = false) public static WebArchive createDeployment() { return ShrinkWrap.create(WebArchive.class, "newsreader.war") .addClasses(RssEntry.class, RssReader.class) .addAsWebResource(WEBAPP_SRC, "index.xhtml") .addAsWebResource(WEBAPP_SRC, "news.xhtml") .addAsWebResource(WEBAPP_SRC + "js-css", "jquery-min.js") // etc. etc. - exhausting.. }
Instead, I took advantage of the Maven lifecycle. By definition, the application must be shipped before the build enters the integration test phase. Arquillian enables to deploy an existing war by using the ZipImporter utility:
@Deployment(testable = false) public static WebArchive deploy() { return ShrinkWrap.create(ZipImporter.class, "newsreader.war") .importFrom(new File("target/newsreader.war")) .as(WebArchive.class); }
To make it happen I had to ensure my tests would truly be run as integration tests. A matter of extra configuration in the pom.xml:
<plugins> .. <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <version>2.12.1</version> <executions> <execution> <goals> <goal>integration-test</goal> <goal>verify</goal> </goals> </execution> </executions> </plugin> .. </plugins>
To save me a bit of configuration effort I adhered to naming conventions and let my test class name end with IT, a.k.a. Integration Test.
Another interesting part were UI interactions, mainly page transitions. In general, I have to say that Graphene Selenium along with jQuery locators proved excellent for this job:
.. import org.jboss.arquillian.drone.api.annotation.Drone; import org.jboss.arquillian.ajocado.framework.GrapheneSelenium; import org.jboss.arquillian.ajocado.locator.JQueryLocator; import static org.jboss.arquillian.ajocado.Graphene.jq; @Drone private GrapheneSelenium browser; private static final JQueryLocator HOME_PAGE = jq("#home"); ..
jQuery Mobile adds animation when a page transition is made and favors Ajax calls over the full page load. This was not a problem as long as the pages remained in a single file (jQuery sees a page as a div). Capturing a successful page load worked like a dream via the following one liner:
browser.waitForCondition(Graphene.elementVisible.locator(HOME_PAGE).getJavaScriptCondition(), 6000);
The news page however was a bit slower to load. First, because the news had to be fetched from a third-party publication server. Secondly, a full page load was needed. I was struggling to capture the moment the page was ready for subsequent tests. The problem was resolved by instructing Graphene to wait for a full page load:
browser.waitForPageToLoad(6000);
Next issue I had, still with page transitions, was capturing screenshots. As I mentioned in my previous post I really appreciate the possibility to document test results by taking screenshots. With the news page however the screenshot seemed to be taken way too early, when the page was still being loaded. I could not understand why since my tests claimed the exact opposite (that the page had already been loaded). Eventually, I realized the issue can be solved by instructing Graphene to add a minimum delay between individual UI actions. Thus, in arquillian.xml:
<extension qualifier="graphene"> .. <property name="seleniumSpeed">100</property> .. </extension>
Actually, the whole Arquillian’s Drone extension is highly configurable. Lesson learned – be familiar with default settings and what effect do they have.
Finally, the data. News as such are read from Yahoo. Their content is never known upfront. Also, they vary in structure. Mostly an image is provided but sometimes it is missing. When testing the incoming news I limited the scope to a bare minimum. My only requirement was that any link included in the news feed must be valid. The respective test would go through all the links in the feed and verify every single one of them (click the link, wait for page load, press browser back button):
private void assertLink(JQueryLocator link) { browser.highlight(link); browser.click(link); browser.waitForPageToLoad(6000); browser.goBack(); }
That concludes my thoughts on advanced integration tests with Arquillian. I find the tool absolutely amazing and hope it will stay tuned.
Download Source Code or Explore It