Automation has arguably done more to improve the development lifecycle in recent years than virtually anything else. As applications have become increasingly complex, iterative, and distributed, we seek to automate the software development process even further, beyond such mainstream development practices as automated source control and nightly build systems, towards automating integration and testing.
Continuous integration is one such "next step," one that can be extended to also automate certain kinds of testing. In this article, I extend continuous integration systems to perform integration, performance, and load testing. While this discussion uses Java EE and associated tools, the concepts are equally applicable to other platforms.
Continuous Integration Basics
Continuous integration is a software engineering process where an application under development is completely rebuilt and tested frequently and automatically. While not an entirely new concept, the term was coined by Martin Fowler in a paper (martinfowler.com/articles/continuousIntegration.html) and grew in popularity as part of extreme programming (XP) practices and methodologies.
Many of us have horror stories of working on large development teams, where we each worked independently on our portions of an application, then spent as long (or longer) integrating all the pieces together into a working application. Part of the appeal of XP is the notion of integrating the application continually when new code is checked in, or at least several times a day.
A continuous integration process requires (paraphrased from Fowler's paper):
- A single code repository. (I use Subversion, but you could use others like CVS, Perforce, and so on.)
- Automated build process with self-testing. (I use Apache Ant, you could use Maven.)
- Daily code commits.
- Continuous integration server that can build, integrate, and test the entire application quickly.
- Ability to test in a clone of production environment.
- Ability to broadcast overall build status.
- Ability to automatically deploy and broadcast availability of builds.
Continuous integration processes go beyond simply ensuring that the automating build compiles cleanly. To declare a build to be successful, it must pass basic functional tests. So we do need a somewhat mature development process, where teams all work from the same code repository, write a test case for the functionality they develop, build and test their functionality locally, refactor, and verifyonly then committing their changes (frequently, at least daily) to the source code repository.
The continuous integration server includes functionality that detects that code has changed, checks out the code, and then builds and tests the entire application in a clean environment, eliminating the vagaries of individual developer's environments. If the build or tests fail, developers are notified immediately, when they are most able to easily and quickly fix the problem they introduced.
That's the process, simplified. For large applications, we often need to set up a staged build process, which lets us reduce the time needed to build and test (testing is usually what takes the most time).