| Prev | Next |
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 | ||
This chapter provides an overview of Continuous Integration summarizing the technique and its application with PHPUnit.
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.
This is where a framework for continuous build processes such as CruiseControl comes into play. It 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.
cd /usr/local/cruisecontrolmkdir -p projects/BankAccount/build/logscd projects/BankAccountsvn co svn://svn.phpunit.de/phpunit/phpunit/branches/release/3.2/PHPUnit/Samples/BankAccount sourcebuild.xml file.Example 19.1: projects/BankAccount/build.xml
<project name="BankAccount" 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/bankaccount.xml BankAccountTest"/>
</exec>
</target>
<target name="build" depends="checkout,test"/>
</project>cd /usr/local/cruisecontrolconfig.xml file.Example 19.2: config.xml
<cruisecontrol>
<project name="BankAccount" 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.
./cruisecontrol.shhttp://localhost:8080/ in your webbrowser.
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.
pear install --alldeps phpunit/phpUnderControlphpuc install /usr/local/cruisecontrolphpuc project --version-control svn
--version-control-url svn://svn.phpunit.de/phpunit/phpunit/branches/release/3.3/PHPUnit/Samples/BankAccount
--test-case BankAccountTest
--test-file BankAccountTest.php
--test-dir .
--project-name BankAccount
/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.
cd /usr/local/cruisecontrol./cruisecontrol.shhttp://localhost:8080/ in your webbrowser.Apache Maven is a software project management and comprehension tool. Based on the concept of a Project Object Model (POM), Apache Maven can manage a project's build, reporting and documentation from a central place of information.
The single XML logfile that PHPUnit's XML logging facility (see the section called “XML Format”) generates needs to be split into separate XML
logfiles, one for each test suite, before it can be processed by Apache
Maven's surefire plugin.
This plugin is used during the test phase of the build lifecycle to
execute the unit tests of an application. Example 19.4
shows an XSLT stylesheet that performs this splitting. Example 19.3 shows an
example pom.xml configuration file.
Example 19.3: pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- ... -->
<prerequisites>
<maven>2.0.7</maven>
</prerequisites>
<!-- ... -->
<build>
<!-- ... -->
<plugins>
<plugin>
<dependencies>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant-trax</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>net.sf.saxon</groupId>
<artifactId>saxon</artifactId>
<version>8.7</version>
</dependency>
</dependencies>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.2-SNAPSHOT</version>
<executions>
<execution>
<id>codecoverage</id>
<phase>pre-site</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<property name="phpunit.codecoverage"
location="${project.reporting.outputDirectory}/phpunit/codecoverage" />
<property name="surefire.reports"
location="${project.build.directory}/surefire-reports" />
<mkdir dir="${phpunit.codecoverage}"/>
<mkdir dir="${surefire.reports}"/>
<!-- ${ant.phpunit} path to PHPUnit executable -->
<!-- ${ant.pear};... this is the include path for your test execution -->
<!-- ${test.AllTests} PHPUnit cmd line args like 'AllTests de/dmc/dashboard/AllTests.php' -->
<exec executable="${ant.phpunit}" dir="${basedir}">
<arg line="-d include_path=${ant.pear};${project.build.sourceDirectory};${project.build.testSourceDirectory}
--report ${phpunit.codecoverage} ${test.AllTests}" />
</exec>
<xslt in="${phpunit.codecoverage}/logfile.xml"
out="${surefire.reports}/xslt.info"
style="src/test/config/phpunit_to_surefire.xslt"
processor="trax">
<!-- this is the output folder for surefire like XML Reports -->
<param name="outputDir" expression="${surefire.reports}"/>
</xslt>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>2.4-SNAPSHOT</version>
<reportSets>
<reportSet>
<reports>
<report>report-only</report>
</reports>
</reportSet>
</reportSets>
</plugin>
</plugins>
</reporting>
</project>Example 19.4: phpunit_to_surefire.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="outputDir">.</xsl:param>
<xsl:template match="testsuites">
<xsl:apply-templates select="testsuite"/>
</xsl:template>
<xsl:template match="testsuite">
<xsl:if test="testcase">
<xsl:variable name="outputName" select="./@name"/>
<xsl:result-document href="file:///{$outputDir}/{$outputName}.xml" method="xml">
<xsl:copy-of select="."/>
</xsl:result-document>
</xsl:if>
<xsl:apply-templates select="testsuite"/>
</xsl:template>
</xsl:stylesheet>
| Prev | Next |
Copyright © 2005-2009 Sebastian Bergmann.