Testing JSF and RichFaces with Arquillian - Part II - Rapid Test Development
June 5, 2013
In a previous post we have discussed what technologies we use for testing JSF and RichFaces in particular.
The tools we use focus on testing complex business applications with rich user interfaces. But as the complexity of an application evolves, the level of the abstraction can grow unwieldy.
Fortunatelly Arquillian allows us to tame the complexity and get an application’s evolution under control. As Arquillian focuses on testing the real behavior of an application in its real integration environment, it gives you a satisfactory feeling that what you have done really will work in production.
Real Stuff – It Must Be Slow(?)
However leveraging real stuff for testing (the same as with magic) always comes with a price: it is usually hard to set up and slow to execute. That’s why it is pretty boring, isn’t it?
With the right tools employed, you can achieve a really fast test development approach that will make testing fun again!
Fast Development Turnaround
Running Test from an IDE
Really. With Arquillian, you can always run the integration test from an IDE. In fact, it is the preferred way to develop and debug tests.
Doing so will avoid the need to bootstrap the build system and save you some (or rather a lot of) cycles.
This will save you the time needed to intialize the container and all you need to do is to deploy the application (which itself can be time-consuming, as you can read below).
When constructing an application deployment, you should use as minimal a deployment as possible. Period.
It will then take less time to construct the deployable archive and it can be deployed to the container faster.
As it might be time-consuming to split the application into it’s simplest possible pieces and allow for the composition of micro-deployments, it is still a very useful tool in the early stages of application development.
In the prototyping stage, you can simply implement against stub implementations of real interfaces that your application will need to integrate with at the end.
Avoiding Unnecessary Initialization
Even if you decide not to split the deployment into micro-deployments, you should nevertheless give special attention to minimizing the time the application needs to initialize after deployment.
Doing so can save you addtional time for both you and your colleages. And you just need to decide whether (e.g. for testing JSF views) the messaging system is really in fact necessary.
Reusable Remote Selenium Session
Selenium / WebDriver is an outstanding helper for browser automation, but it is very demanding when it comes to it’s initialization. Usually Selenium itself needs to be started first and then you can connect to it and request the creation of a browser session.
Luckily, the architecture of Selenium allows you to use not only direct control over the browser, but you can also use a remote session – you connect the test to the Selenium Server which is already started.
Furthermore, you can also connect to a running browser – by Drone’s exclusive browser session reuse feature.
This way the test will not need to start anything, it will just connect to the instance of a browser which is already running and request the page directly.
Okay, I might not be convincing you yet, so let’s see a real life scenario and execute a test from the command line:
$ mvn verify -Dintegration=jbossas71 -Dbrowser=chrome -DskipTests=true -Dgeneration.skip=true -Doptimization.skip=true -Darquillian.container.uninstall=false -Dtest=ITTableState
When we execute a specific test case from the Maven CLI, it executes in 33.6s (considering that some unnecessary steps were disabled).
Because we have actually executed 5 tests from the integration case ITTableState, we can further improve the execution time just by selecting one particular test – let’s execute the test from our IDE.
The IDE reports we have executed a specific test method in 19.0s. That’s a fair improvement.
How is it possible?
The Maven build itself is able to do incremental builds (as long as the plugins you use support it). Even though, the plugin needs to be always initiated just to check that nothing changed. The IDE is smarter here as it does an incremental build when the source code changes. When you execute the test, everything is already built and you don’t need to spend any extra time by doing a build of the application.
Okay, but I promised you we can a significant improvement of the test execution time – let’s see how close to zero execution time we can go.. ;-)
When I start noth the application server and the Selenium Server, I’m pretty prepared to do the job right way.
When I execute the test for the first time, it takes 12.9s. But what happens is that the browser window is opened by Selenium Server and it remains open after the test finishes. Let’s run the test again.
For the second test run, it now takes just 6.5s. That’s FIVE time less than when we executed the test for the first time.
But there is not only the advantage of repeated time savings, there is a similarly huge impact on the psychological side of things. Your brain does not do a (harmful) context switch on the order of seconds. So once the test finishes, you are still focused on the task and it’s tiny details – provided the test finishes quickly enough.
For a critics’ eyes: you can still save some additional time: when you disable Arquillian’s deployment management, deploy the test into the container before the execution, and provide the URL of a application directly to the test, then the execution of the test alone goes down to 1.7s. At least half ot this time is spent in an initialization of a Arquillian Core.
Don’t blame Arquillian – the big portion of this overhead which Arquillian gives to the execution is caused by initializations which happen once per test suite, so during over several runs, you won’t feel it at all. But during development, it can matter! And we are working on that. :-)
As you can saw, with the right tools in place, you can achieve incredibly fast testing turnaround.
In the next parts of this series, we will focus on: