Prev Next

Chapter 21. Continuous Integration

This chapter provides an overview of Continuous Integration summarizing the technique and its application with PHPUnit.

 

Continuous Integration is a software development practice where members of a team integrate their work frequently, usually each person integrates at least daily, leading to multiple integrations per day. Each integration is verified by an automated build (including test) to detect integration errors as quickly as possible. Many teams find that this approach leads to significantly reduced integration problems and allows a team to develop cohesive software more rapidly.

 
 --Martin Fowler

Continuous Integration demands a fully automated and reproducible build, including testing, that runs many times a day. This allows each developer to integrate daily thus reducing integration problems. While this can be achieved by setting up a cronjob that makes a fresh checkout from the project's source code repository at regular intervals, runs the tests, and publishes the results, a more comfortable solution may be desired.

Atlassian Bamboo

Atlassian Bamboo is a Continuous Integration (CI) server that assists software development teams by providing automated building and testing of software source-code status, updates on successful/failed builds, and reporting tools for statistical analysis.

The following example assumes that the Bamboo distribution archive has been unpacked into /usr/local/Bamboo.

  1. cd /usr/local/Bamboo
  2. Edit the webapp/WEB-INF/classes/bamboo-init.properties file.

  3. Optionally install the bamboo-checkstyle plugin.

Example 21.1: bamboo-init.properties

bamboo.home=/usr/local/Bamboo


  1. ./bamboo.sh start
  2. Open http://localhost:8085/ in your webbrowser.

  3. Follow the guided installation instructions.

  4. Configure Apache Ant as a Builder in the Administration panel.

Bamboo is now configured and we can set up a project plan. First we need a project, though. For the purpose of this example lets assume we have a copy of the Money sample that ships with PHPUnit in a Subversion repository (file:///var/svn/money). Together with the *.php files we also have the following Apache Ant build script (build.xml) in the repository.

Example 21.2: build.xml

<project name="Money" default="build">
 <target name="clean">
  <delete dir="${basedir}/build"/>
 </target>

 <target name="prepare">
  <mkdir dir="${basedir}/build"/>
  <mkdir dir="${basedir}/build/logs"/>
 </target>

 <target name="phpcs">
  <exec dir="${basedir}"
        executable="phpcs"
        output="${basedir}/build/logs/checkstyle.xml"
        failonerror="false">
   <arg line="--report=checkstyle ." />
  </exec>
 </target>

 <target name="phpunit">
  <exec dir="${basedir}" executable="phpunit" failonerror="true">
   <arg line="--log-xml         ${basedir}/build/logs/phpunit.xml
              --coverage-clover ${basedir}/build/logs/clover.xml
              --coverage-html   ${basedir}/build/coverage
              MoneyTest" />
  </exec>
 </target>

 <target name="build" depends="clean,prepare,phpcs,phpunit"/>
</project>


Now that we have a project, we can create a plan for it in Bamboo.

  1. Open http://localhost:8080/ in your webbrowser.

  2. Follow the guided "Create a Plan" instructions.

  3. In step 3 of "Create a Plan", check the "The build will produce test results" and "Clover output will be produced" options and provide the paths to the XML files produced by PHPUnit.

    If you installed the bamboo-checkstyle plugin also check the "CheckStyle output will be produced" option and provide the path of the XML file produced by PHP_CodeSniffer.

  4. In step 5 of "Create a Plan", set up an artifact for the HTML files (*.*, build/coverage) that PHPUnit produces.

CruiseControl

CruiseControl is a framework for continuous build processes and includes, but is not limited to, plugins for email notification, Apache Ant, and various source control tools. A web interface is provided to view the details of the current and previous builds.

The following example assumes that CruiseControl has been installed into /usr/local/cruisecontrol.

  1. cd /usr/local/cruisecontrol
  2. mkdir -p projects/Money/build/logs
  3. cd projects/Money
  4. svn co file:///var/svn/money source
  5. Edit the build.xml file.

Example 21.3: projects/Money/build.xml

<project name="Money" default="build" basedir=".">
 <target name="checkout">
  <exec dir="${basedir}/source/" executable="svn">
   <arg line="up"/>
  </exec>
 </target>

 <target name="test">
  <exec dir="${basedir}/source" executable="phpunit" failonerror="true">
   <arg line="--log-xml ${basedir}/build/logs/phpunit.xml MoneyTest"/>
  </exec>
 </target>

 <target name="build" depends="checkout,test"/>
</project>


  1. cd /usr/local/cruisecontrol
  2. Edit the config.xml file.

Example 21.4: config.xml

<cruisecontrol>
  <project name="Money" buildafterfailed="false">
    <plugin
    name="svnbootstrapper"
    classname="net.sourceforge.cruisecontrol.bootstrappers.SVNBootstrapper"/>
    <plugin
    name="svn"
    classname="net.sourceforge.cruisecontrol.sourcecontrols.SVN"/>

    <listeners>
      <currentbuildstatuslistener file="logs/${project.name}/status.txt"/>
    </listeners>

    <bootstrappers>
      <svnbootstrapper localWorkingCopy="projects/${project.name}/source/"/>
    </bootstrappers>

    <modificationset>
      <svn localWorkingCopy="projects/${project.name}/source/"/>
    </modificationset>

    <schedule interval="300">
      <ant
      anthome="apache-ant-1.7.0"
      buildfile="projects/${project.name}/build.xml"/>
    </schedule>

    <log dir="logs/${project.name}">
      <merge dir="projects/${project.name}/build/logs/"/>
    </log>

    <publishers>
      <currentbuildstatuspublisher
      file="logs/${project.name}/buildstatus.txt"/>

      <email
      mailhost="localhost"
      buildresultsurl="http://cruise.example.com/buildresults/${project.name}"
      skipusers="true"
      spamwhilebroken="true"
      returnaddress="project@example.com">
        <failure address="dev@lists.example.com" reportWhenFixed="true"/>
      </email>
    </publishers>
  </project>
</cruisecontrol>


Now we can (re)start the CruiseControl server.

  1. ./cruisecontrol.sh
  2. Open http://localhost:8080/ in your webbrowser.

phpUnderControl

phpUnderControl is an extension for CruiseControl that integrates several PHP development tools, such as PHPUnit for testing, PHP_CodeSniffer for static code analysis, and PHPDocumentor for API documentation generation. It comes with a powerful command-line tool that can, among other things, automatically create CruiseControl's XML configuration files for your project. The following example assumes that CruiseControl has been installed into /usr/local/cruisecontrol.

  1. pear install --alldeps phpunit/phpUnderControl
  2. phpuc install /usr/local/cruisecontrol
  3. phpuc project --version-control svn
                  --version-control-url file:///var/svn/money
                  --test-case MoneyTest
                  --test-file MoneyTest.php
                  --test-dir .
                  --project-name Money
                  /usr/local/cruisecontrol

The above command creates the project directory and the project's build.xml configuration file, performs the initial checkout from the source repository, and adds the new project to the global config.xml configuration file. Now we can (re)start the CruiseControl server.

  1. cd /usr/local/cruisecontrol
  2. ./cruisecontrol.sh
  3. Open http://localhost:8080/ in your webbrowser.

Prev Next
1. Automating Tests
2. PHPUnit's Goals
3. Installing PHPUnit
4. Writing Tests for PHPUnit
Test Dependencies
Data Providers
Testing Exceptions
Testing PHP Errors
5. The Command-Line Test Runner
6. Fixtures
More setUp() than tearDown()
Variations
Sharing Fixture
Global State
7. Organizing Tests
Composing a Test Suite Using the Filesystem
Composing a Test Suite Using XML Configuration
Using the TestSuite Class
8. TestCase Extensions
Testing Output
9. Database Testing
Data Sets
Flat XML Data Set
XML Data Set
CSV Data Set
Replacement Data Set
Operations
Database Testing Best Practices
10. Incomplete and Skipped Tests
Incomplete Tests
Skipping Tests
11. Test Doubles
Stubs
Mock Objects
Stubbing and Mocking Web Services
Mocking the Filesystem
12. Testing Practices
During Development
During Debugging
13. Test-Driven Development
BankAccount Example
14. Behaviour-Driven Development
BowlingGame Example
15. Code Coverage Analysis
Specifying Covered Methods
Ignoring Code Blocks
Including and Excluding Files
16. Other Uses for Tests
Agile Documentation
Cross-Team Tests
17. Skeleton Generator
Generating a Test Case Class Skeleton
Generating a Class Skeleton from a Test Case Class
18. PHPUnit and Selenium
Selenium RC
PHPUnit_Extensions_SeleniumTestCase
19. Logging
Test Results (XML)
Test Results (TAP)
Test Results (JSON)
Code Coverage (XML)
20. Build Automation
Apache Ant
Apache Maven
Phing
21. Continuous Integration
Atlassian Bamboo
CruiseControl
phpUnderControl
22. PHPUnit API
Overview
PHPUnit_Framework_Assert
assertArrayHasKey()
assertClassHasAttribute()
assertClassHasStaticAttribute()
assertContains()
assertContainsOnly()
assertEqualXMLStructure()
assertEquals()
assertFalse()
assertFileEquals()
assertFileExists()
assertGreaterThan()
assertGreaterThanOrEqual()
assertLessThan()
assertLessThanOrEqual()
assertNotNull()
assertObjectHasAttribute()
assertRegExp()
assertSame()
assertSelectCount()
assertSelectEquals()
assertSelectRegExp()
assertStringEndsWith()
assertStringEqualsFile()
assertStringStartsWith()
assertTag()
assertThat()
assertTrue()
assertType()
assertXmlFileEqualsXmlFile()
assertXmlStringEqualsXmlFile()
assertXmlStringEqualsXmlString()
PHPUnit_Framework_Test
PHPUnit_Framework_TestCase
PHPUnit_Framework_TestSuite
PHPUnit_Framework_TestResult
Package Structure
23. Extending PHPUnit
Subclass PHPUnit_Framework_TestCase
Assert Classes
Subclass PHPUnit_Extensions_TestDecorator
Implement PHPUnit_Framework_Test
Subclass PHPUnit_Framework_TestResult
Implement PHPUnit_Framework_TestListener
New Test Runner
A. Assertions
B. Annotations
@assert
@backupGlobals
@backupStaticAttributes
@covers
@dataProvider
@depends
@expectedException
@group
@outputBuffering
@runTestsInSeparateProcesses
@runInSeparateProcess
@test
@testdox
@ticket
C. The XML Configuration File
PHPUnit
Test Suites
Groups
Including and Excluding Files for Code Coverage
Logging
Test Listeners
Setting PHP INI settings, Constants and Global Variables
Configuring Browsers for Selenium RC
D. Index
E. Bibliography
F. Copyright