Tài liệu PHP Objects, Patterns and Practice- P10 - Pdf 87

CHAPTER 20 ■ CONTINUOUS INTEGRATION
429
Chapter 18 to illustrate PHPUnit. I’m going to name it userthing, because it's a thing, with a User object
in it.
First of all, here is a breakdown of my project directory. See Figure 20–1.

Figure 20–1.

Part of a sample project to illustrate CI
As you can see, I’ve tidied up the structure a little, adding some package directories. Within the
code, I’ve supported the package structure with the use of namespaces.
Now that I have a project, I should add it to a version control system.
CI and Version Control
Version control is essential for CI. A CI system needs to acquire the most recent version of a project
without human intervention (at least once things have been set up).
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
CHAPTER 20 ■ CONTINUOUS INTEGRATION
430
You may have noticed that I moved the code for userthing into a directory named trunk. That’s
because I’m going to import the project into Subversion, and the branches, tags and trunk directories
are a useful convention in that system.
Here’s the import:
$ svn import userthing.orig/ file:///var/local/svn/userthing -m'first import'
And here's the checkout.
$ svn checkout file:///var/local/svn/userthing/trunk userthing
I covered Subversion in more detail in Chapter 17.
Now that I have the a local version of my project, I’m going to change my working directory to src/
in order to try out the various tools that my CI implementation will require.
$ cd userthing/src
Unit Tests
Unit tests are the key to continuous integration. It’s no good successfully building a project that

return $suite;
}
}

Note In in this case I've kept my test classes in the global namespace. Where tests have a close or one to one
relationship to the components they test, however, it's often neater to place each test class in the same
namespace as its target, and in a parallel directory structure. That way you can tell at a glance the relationship
between a test and its subject both from the test's namespace and the location of its file.
The PHPUnit_Framework_TestSuite class allows you to collect individual test cases into a suite. Here’s
how I can call this from the command line:
$ phpunit test/UserTests
PHPUnit 3.4.11 by Sebastian Bergmann.
.....
Time: 1 second, Memory: 4.50Mb
OK (5 tests, 6 assertions)
Documentation
Transparency is one of the principles of CI. When you're looking at a build in a Continuous
Integration environment, therefore, it’s important to be able to check that the documentation is up to
date, and covers the most recent classes and methods. I examined phpDocumentor in Chapter 16, so
I’ve already run an install like this.
pear upgrade PhpDocumentor
I’d better run the tool just to be sure:
$ mkdir docs
$ phpdoc --directory userthing --target docs/
That generates some pretty bare documentation. Once that’s published on a CI server, I’m sure to
be shamed into writing some real inline documentation.
Code Coverage
It’s no good relying on tests if they don’t apply to the code you have written. PHPUnit includes the
ability to report on code coverage. Here's an extract from PHPUnit’s usage information.
--coverage-html <dir> Generate code coverage report in HTML format.

I can argue all day about the best place to put a brace, whether to indent with tabs or spaces, how to
name a private property variable. Wouldn’t it be nice if I could enforce my prejudices with a tool? Thanks
to PHP_CodeSniffer I can. CodeSniffer can apply one of a set of coding standards to a project and
generate a report, telling you just how bad your style is.
That might sound like a massive pain in the rear end. In fact, it can be just that. But there are
sensible non-passive aggressive uses for a tool like this. I’ll get to these, but first I’ll put the tool through
its paces. Installation first:
$ sudo pear install PHP_CodeSniffer
Now I’m going to apply the Zend coding standard to my code:
$ phpcs --standard=Zend userthing/persist/UserStore.php
FILE: ...userthing/src/userthing/persist/UserStore.php
--------------------------------------------------------------------------------
FOUND 10 ERROR(S) AND 0 WARNING(S) AFFECTING 8 LINE(S)
--------------------------------------------------------------------------------
6 | ERROR | Opening brace of a class must be on the line after the definition
7 | ERROR | Private member variable "users" must contain a leading underscore
9 | ERROR | Opening brace should be on a new line
13 | ERROR | Multi-line function call not indented correctly; expected 12
| | spaces but found 16
...
Clearly, I’d have to adjust my style to submit code to Zend!
It makes sense however, for a team to define coding guidelines. In fact, the decision as to which set
of rules you choose is probably less important than the decision to abide by a common standard in the
first place. If a codebase is consistent, then it’s easier to read, and therefore easier to work with. Naming
conventions, for example, can help to clarify the purpose of variables or properties.
Coding conventions can play a role in reducing risky or bug-prone code as well.
This is a dangerous area, though. Some style decisions are highly subjective, and people can be
disproportionately defensive about their way of doing things. CodeSniffer allows you to define your own
rules, so I suggest that you get buy in from your team on a set of rules so that no one feels that their
coding life has become a coding nightmare.

Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
CHAPTER 20 ■ CONTINUOUS INTEGRATION
435

Figure 20–3.

PHP code browser
Build
While it’s possible to assess code in place, you should all also check that you can build and deploy a
package. To that end, I’ve included a package.xml file in my package. Here I test the build and install
stages.
$ pear package
Analyzing userthing/domain/User.php
Analyzing userthing/util/Validator.php
Analyzing userthing/persist/UserStore.php
Warning: in UserStore.php: class "UserStore" not prefixed with package name "userthing"
Warning: in Validator.php: class "Validator" not prefixed with package name "userthing"
Warning: in User.php: class "User" not prefixed with package name "userthing"
Warning: Channel validator warning: field "date" - Release Date "2010-03-07" is not today
Package userthing-1.2.1.tgz done
Tag the released code with `pear svntag package.xml'
(or set the SVN tag userthing-1.2.1 by hand)
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
CHAPTER 20 ■ CONTINUOUS INTEGRATION
436
Some of those warnings are a little out of date, since my classes use namespaces rather than the
package underscore convention. Nevertheless, I have a successful build. Now to deploy.
$ pear install --force userthing-1.2.1.tgz
install ok: channel://pear.appulsus.com/userthing-1.2.1
So I have a lot of useful tools I can use to monitor my project. Of course, left to myself I’d soon lose

yum install java-1.6.0-openjdk-devel
In a Debian system this should do the job
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
CHAPTER 20 ■ CONTINUOUS INTEGRATION
437
sudo apt-get install sun-java6-jdk
Otherwise, you can get Java directly from www.java.com.
Once you’ve confirmed that you have java (the java website will tell you if you haven’t), you need to
acquire CruiseControl. You can download the latest version at
http://cruisecontrol.sourceforge.net/download.html. You should end up with an archive named
something like cruisecontrol-bin-2.8.3.zip. Now you can move the directory somewhere central, and
launch the CruiseControl script.
$ unzip cruisecontrol-bin-2.8.3.zip
$ mv cruisecontrol-bin-2.8.3 /usr/local/cruisecontrol

$ cd /usr/local/cruisecontrol/
$ export JAVA_HOME=/usr/lib/jvm/java-1.6.0-openjdk/
$ ./cruisecontrol.sh
Notice that export line. Like many Java applications CruiseControl needs to know where your java
executable resides. You can see where that is on my system. Your system may differ. You can try
something like
ls -al `which java`
or
locate javac | grep bin
to find the directory you should use for JAVA_HOME. The java and javac (that’s the java compiler)
binaries will usually be found in a directory named bin. You should include the parent directory, and not
bin itself, in JAVA_HOME.

Note Once you’ve got your proof of concept up and running, you may want ensure that CruiseControl starts up
automatically when you boot your integration server. An excellent blog entry by Felix De Vliegher at

Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
CHAPTER 20 ■ CONTINUOUS INTEGRATION
439
$ phpuc --usage
Usage: phpuc.php <command> <options> <arguments>
For single command help type:
phpuc.php <command> --help
Available commands:
* clean Removes old build artifacts and logs for a specified project.
* delete Deletes a CruiseControl project with all logs and artifacts.
* example Creates a small CruiseControl example.
* graph Generates the metric graphs with ezcGraph
* install Installs the CruiseControl patches.
* merge-phpunit Merges a set of PHPUnit logs into a single new file.
* project Creates a new CruiseControl project.
So, I’ve already installed the package onto my system. Now I need to amend the CruiseControl
environment to support phpUnderControl. As you can see, phpuc provides a second installation step: a
command named install.

Note This two-part installation mechanism is a useful one. PEAR is good at getting library code, runnable
scripts, and supporting data files in place. When it comes to complex installation for things like Web applications
and database driven systems, it’s often a good idea to provide a configurable installation command as part of your
application. Of course, Phing would be a good choice for this secondary installation. Most users won’t have Phing
to hand though, so it can be better to build the installation logic into an application command.
$ phpuc install /usr/local/cruisecontrol/
Now to restart CruiseControl
$ cd /usr/local/cruisecontrol/
$ kill `cat cc.pid`
$ ./cruisecontrol.sh
CruiseControl stores its process id in a file called cc.pid. I use that to kill the current process, then I

XML elements at the time of this writing. You’ll likely use it when you start to delve deeper into CI. As
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
CHAPTER 20 ■ CONTINUOUS INTEGRATION
441
useful as the documentation is, it might give you the impression that you won’t be up and running with
a build and test cycle any time soon.
phpuc comes to the rescue, though, with the project command. This creates the required files and
directories, and amends any configuration files.
phpuc project --source-dir src \
--version-control svn \
--version-control-url file:///var/local/svn/userthing/trunk \
--test-dir test \
--test-case UserTests \
--test-file UserTests.php \
--coding-guideline Zend \
--project-name userthing \
/usr/local/cruisecontrol/

Note If I were running CruiseControl on system remote from my version control repository, I’d also want to set
the
user
and
password
options.
Much of this should be self-explanatory. CruiseControl will need access to the userthing source, so,
through phpuc, I need to tell it I’m using Subversion, and provide it with the URL for the code. Then I tell
it where to find the tests, the coding standard I wish to apply. To set things up, phpUnderControl needs
to know where to find the cruisecontrol directory, so I provide the path. The output of the phpuc
project command gives you a good idea of the work that needs to be done in order to pass on this
information.

1. Modifying config file: config.xml
phpuc helpfully tells you exactly what it’s up to. As you can see it amends one or both of config.xml
and build.xml for each of the tasks I want CruiseControl to run.
By the time you read this, running phpuc in this way might be enough to get you up and running. At
the time of this writing though, there are a few issues that must first be addressed. phpUnderControl is a
beta product, after all.
First of all phpuc writes an element to the config.xml file that CruiseControl 2.8.3 chokes on. If you
find this line in config.xml:
<currentbuildstatuspublisher file="logs/${project.name}/buildstatus.txt"/>
and either comment it out, or delete it, you should avoid a fatal error.
Secondly, phpuc writes a call to itself into the main configuration file at config.xml. Here’s the
relevant section:
<project name="userthing" buildafterfailed="false">
<!-- ... -->

<publishers>
<!-- ... -->

<execute command="/usr/bin/phpuc graph logs/${project.name}
artifacts/${project.name}"/>
</publishers>

</project>
CruiseControl allows you to add your own publishers to provide custom reports for the user.
Unfortunately, there is a bug with the phpuc graph command that, at the time of this writing, prevents
the command from running. The workaround is to remove a file from the PEAR repository:
$ rm /usr/share/pear/phpUnderControl/Graph/Input/ClassComplexityInput.php
where /usr/share/pear is my PEAR directory. You can find yours with the command:
$ pear config-get php_dir
Since this problem may be fixed by now, you might skip this step, but bear it mind if the project

<target name="build" depends="checkout,php-documentor,php-codesniffer,phpunit"/>
<!-- ... -->

<target name="phpunit">
<exec executable="phpunit" dir="${basedir}/source" failonerror="on">
<arg line=" --log-junit ${basedir}/build/logs/phpunit.xml
--coverage-clover ${basedir}/build/logs/phpunit.coverage.xml
--coverage-html ${basedir}/build/coverage UserTests test/UserTests.php"/>
</exec>
</target>

</project>
As you can see, this is just the same as a Phing document. It’s divided into target elements, which
relate to one another via their depends attributes. The phpunit task would fail as it stands. It’s calling
test/UserTest.php, but from the context of ${basedir}/source. In order to make this work, all I need do
is amend the exec element, so that it runs from ${basedir}/source/src.
<exec executable="phpunit" dir="${basedir}/source/src" failonerror="on">
Now, I’m about ready to run my project.
Running phpUnderControl / CruiseControl
First of all I need to restart CruiseControl:
$ kill `cat cc.pid`
$ ./cruisecontrol.sh
Now, I can see the results of my initial build by visiting http://localhost:8080/cruisecontrol. The
control panel should show that the userthing project has been added, and indicate the outcome of the
build. Clicking on the project name will call up the Overview screen.
You can see this screen in Figure 20–6.
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
CHAPTER 20 ■ CONTINUOUS INTEGRATION
444



$user = $this->store->getUser( $mail );
if ( is_null( $user ) ) {
return null;
}

if ( $user->getPass() == $pass ) {
return true;
}

Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
CHAPTER 20 ■ CONTINUOUS INTEGRATION
446
$this->store->notifyPasswordFailure( $mail );
return false;
}
See how I’ve sabotaged the method? As it now stands validateUser() will always return false.
Here's the test that should choke on that. It’s in test/ValidatorTest.php:
public function testValidate_CorrectPass() {
$this->assertTrue(
$this->validator->validateUser( "[email protected]", "12345" ),
"Expecting successful validation"
);
}
Having made my change, all I need do is commit, and wait. Sure enough, before long, my status page
highlights userthing in an alarming orangey red. Once I’ve clicked on the project name, I select the
Tests tab. You can see the error report in Figure 20–9

Figure 20–9.



Note If you want more verbose messages you should look at the
htmlemail
publisher, which shares a common
set of attributes and child elements with the
email
publisher, but also provides additional options to help you
format an inline message. You can find more information about
htmlemail
at
http://cruisecontrol.sourceforge.net/main/configxml.html#htmlemail.
Adding Your Own Build Targets
So far I have stuck to the toolset supported by phpUnderControl. That gets us a long way, after all.
However you should know that you can quite easily add your own checks to CruiseControl.
The biggest omission so far has been a test of for creating and installing a package. This is
significant, because CI is about build as well as testing. One approach would be to create a PHPUnit test
case which attempts to build and install a package.
In order to illustrate some of CruiseControl's features, though, I propose to perform the build and
install from within the product build file. I’ve already shown you the build target. It invokes the other
targets in the file through its depends attribute. Here I add a new dependency.
<target name="build"
depends="checkout,php-documentor,php-codesniffer,phpunit,install-package"/>
The install-package target does not exist yet. Time to add it.
<target name="make-package">
<exec executable="pear" dir="${basedir}/source/src"
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
CHAPTER 20 ■ CONTINUOUS INTEGRATION
448
failonerror="on"
output="${basedir}/build/builderror/index.txt">


Nhờ tải bản gốc
Music ♫

Copyright: Tài liệu đại học © DMCA.com Protection Status