<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<feed xmlns="http://www.w3.org/2005/Atom">

	<title>Planet PHPUnit</title>
	<link rel="self" href="http://planet.phpunit.de/atom.xml"/>
	<link href="http://planet.phpunit.de/"/>
	<id>http://planet.phpunit.de/atom.xml</id>
	<updated>2010-09-02T23:00:28+00:00</updated>
	<generator uri="http://www.planetplanet.org/">Planet/2.0 +http://www.planetplanet.org</generator>

	<entry xml:lang="en">
		<title type="html">Options for setting up a Doctrine database connection when PHPUnit testing symfony plugins</title>
		<link href="http://test.ical.ly/2010/08/30/options-for-setting-up-a-doctrine-database-connection-when-phpunit-testing-symfony-plugins/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=options-for-setting-up-a-doctrine-database-connection-when-phpunit-testing-symfony-plugins"/>
		<id>http://test.ical.ly/?p=1337</id>
		<updated>2010-08-29T17:00:42+00:00</updated>
		<content type="html">&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/08/database.png&quot;&gt;&lt;img class=&quot;alignleft size-full wp-image-1338&quot; title=&quot;database&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/08/database.png&quot; alt=&quot;&quot; width=&quot;256&quot; height=&quot;256&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It is rarely the case that your unit tests actually test your database. It is however not so rare that the code your unit test tries to cover needs a database connection of some sorts.&lt;/p&gt;
&lt;p&gt;In symfony 1.x you will find quite some tightly coupled code. Together with Doctrines (1.x) implementation of the active record pattern you will get a lot of exceptions complaining about no open database connection.&lt;/p&gt;
&lt;p&gt;So if your tests need a database connection how should you do that?&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1337&quot;&gt;&lt;/span&gt;I created a little experiment to test setting up database connections. If you&amp;#8217;re interested you can reproduce those experiments with &lt;a href=&quot;http://github.com/caefer/sfPhpUnitDbBootstrapExperimentPlugin&quot; target=&quot;_blank&quot;&gt;the sources on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I basically tried a few combinations of the following code.&lt;/p&gt;
&lt;h2&gt;Setting up a database connection using the settings in the fixture projects &lt;em&gt;databases.yml&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h2&gt;Setting up a database connection using Doctrines mock adapter&lt;/h2&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h2&gt;Findings&lt;/h2&gt;
&lt;p&gt;You should always set up a database connection using the &lt;em&gt;setUp()&lt;/em&gt; method of your testcase or a test method itself if it is the only method requiring a database connection. This way you only use the database when you actually need it.&lt;/p&gt;
&lt;p&gt;I am still pretty amazed that using the mock adapter shows no functional difference to &lt;em&gt;sqlite::memory:&lt;/em&gt; and is using up the same amount of memory.&lt;/p&gt;
&lt;p&gt;Using &amp;#8211;process-isolation on PHPUnit when executing a testcase or testsuite will drastically reduce the memory consumption but at the time of writing this (using PHPUnit 3.5RC1) it will produce a strange runtime exception when the database connection is made in the bootstrap file.&lt;/p&gt;
&lt;p&gt;Oh and on the GitHub page you can also see the results of the experiments. &lt;img src=&quot;http://test.ical.ly/wp-includes/images/smilies/icon_smile.gif&quot; alt=&quot;:)&quot; class=&quot;wp-smiley&quot; /&gt; &lt;/p&gt;


&lt;div class=&quot;shr-bookmarks shr-bookmarks-expand shr-bookmarks-bg-shr&quot;&gt;
&lt;ul class=&quot;socials&quot;&gt;
		&lt;li class=&quot;shr-delicious&quot;&gt;
			&lt;a href=&quot;http://delicious.com/post?url=http://test.ical.ly/2010/08/30/options-for-setting-up-a-doctrine-database-connection-when-phpunit-testing-symfony-plugins/&amp;title=Options+for+setting+up+a+Doctrine+database+connection+when+PHPUnit+testing+symfony+plugins&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on del.icio.us&quot;&gt;Share this on del.icio.us&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-linkedin&quot;&gt;
			&lt;a href=&quot;http://www.linkedin.com/shareArticle?mini=true&amp;url=http://test.ical.ly/2010/08/30/options-for-setting-up-a-doctrine-database-connection-when-phpunit-testing-symfony-plugins/&amp;title=Options+for+setting+up+a+Doctrine+database+connection+when+PHPUnit+testing+symfony+plugins&amp;summary=%20It%20is%20rarely%20the%20case%20that%20your%20unit%20tests%20actually%20test%20your%20database.%20It%20is%20however%20not%20so%20rare%20that%20the%20code%20your%20unit%20test%20tries%20to%20cover%20needs%20a%20database%20connection%20of%20some%20sorts.%20In%20symfony%201.x%20you%20will%20find%20quite%20some%20tightly%20coupled%20code.%20Together%20with%20Doctrines%20%281.x%29%20implementation%20of%20the%20&amp;source=test.ical.ly&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on LinkedIn&quot;&gt;Share this on LinkedIn&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-mail&quot;&gt;
			&lt;a href=&quot;mailto:?subject=%22Options%20for%20setting%20up%20a%20Doctrine%20database%20connection%20when%20PHPUnit%20testing%20symfony%20plugins%22&amp;body=Link: http://test.ical.ly/2010/08/30/options-for-setting-up-a-doctrine-database-connection-when-phpunit-testing-symfony-plugins/ (sent via shareaholic)%0D%0A%0D%0A----%0D%0A %20It%20is%20rarely%20the%20case%20that%20your%20unit%20tests%20actually%20test%20your%20database.%20It%20is%20however%20not%20so%20rare%20that%20the%20code%20your%20unit%20test%20tries%20to%20cover%20needs%20a%20database%20connection%20of%20some%20sorts.%20In%20symfony%201.x%20you%20will%20find%20quite%20some%20tightly%20coupled%20code.%20Together%20with%20Doctrines%20%281.x%29%20implementation%20of%20the%20&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Email this to a friend?&quot;&gt;Email this to a friend?&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-misterwong&quot;&gt;
			&lt;a href=&quot;http://www.mister-wong.com/addurl/?bm_url=http://test.ical.ly/2010/08/30/options-for-setting-up-a-doctrine-database-connection-when-phpunit-testing-symfony-plugins/&amp;bm_description=Options+for+setting+up+a+Doctrine+database+connection+when+PHPUnit+testing+symfony+plugins&amp;plugin=sexybookmarks&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Add this to Mister Wong&quot;&gt;Add this to Mister Wong&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-netvibes&quot;&gt;
			&lt;a href=&quot;http://www.netvibes.com/share?title=Options+for+setting+up+a+Doctrine+database+connection+when+PHPUnit+testing+symfony+plugins&amp;url=http://test.ical.ly/2010/08/30/options-for-setting-up-a-doctrine-database-connection-when-phpunit-testing-symfony-plugins/&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Submit this to Netvibes&quot;&gt;Submit this to Netvibes&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-reddit&quot;&gt;
			&lt;a href=&quot;http://reddit.com/submit?url=http://test.ical.ly/2010/08/30/options-for-setting-up-a-doctrine-database-connection-when-phpunit-testing-symfony-plugins/&amp;title=Options+for+setting+up+a+Doctrine+database+connection+when+PHPUnit+testing+symfony+plugins&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on Reddit&quot;&gt;Share this on Reddit&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-stumbleupon&quot;&gt;
			&lt;a href=&quot;http://www.stumbleupon.com/submit?url=http://test.ical.ly/2010/08/30/options-for-setting-up-a-doctrine-database-connection-when-phpunit-testing-symfony-plugins/&amp;title=Options+for+setting+up+a+Doctrine+database+connection+when+PHPUnit+testing+symfony+plugins&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Stumble upon something good? Share it on StumbleUpon&quot;&gt;Stumble upon something good? Share it on StumbleUpon&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-twitter&quot;&gt;
			&lt;a href=&quot;http://twitter.com/home?status=Options+for+setting+up+a+Doctrine+database+connection+when+PHPUnit+testing+symfo%5B..%5D+-+http://bit.ly/cqHwCH&amp;source=shareaholic&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Tweet This!&quot;&gt;Tweet This!&lt;/a&gt;
		&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;/div&gt;
&lt;/div&gt;</content>
		<author>
			<name>Christian</name>
			<uri>http://test.ical.ly</uri>
		</author>
		<source>
			<title type="html">test.ical.ly &#187; phpUnit</title>
			<subtitle type="html">getting PHP by the balls</subtitle>
			<link rel="self" href="http://test.ical.ly/tags/phpunit/feed/atom/"/>
			<id>http://test.ical.ly/feed/atom/</id>
			<updated>2010-09-01T00:00:27+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Why Doctrine_Core::getTable(&amp;#8216;BarFoo&amp;#8217;) is not such a good idea.. when PHPUnit testing a symfony plugin</title>
		<link href="http://test.ical.ly/2010/08/27/why-doctrine_core-gettable-is-not-such-a-good-idea-when-phpunit-testing-a-symfony-plugin/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=why-doctrine_core-gettable-is-not-such-a-good-idea-when-phpunit-testing-a-symfony-plugin"/>
		<id>http://test.ical.ly/?p=1333</id>
		<updated>2010-08-26T20:18:01+00:00</updated>
		<content type="html">&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/08/static.jpg&quot;&gt;&lt;img class=&quot;alignleft size-medium wp-image-1335&quot; title=&quot;static&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/08/static-300x227.jpg&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;227&quot; /&gt;&lt;/a&gt;If you have a look at the symfony and Doctrine documentation you will notice that whenever you want to get the table object for a model you will call Doctrine_Core::getTable(&amp;#8216;ModelName&amp;#8217;).&lt;/p&gt;
&lt;p&gt;Apparently this is considered a best practice however I came to thing quite the opposite.&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1333&quot;&gt;&lt;/span&gt;As you probably know I am quite keen on the topic of unit testing and that is exactly where Doctrine_Core::getTable() gets annoying.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s a static method that will be called in many methods of your classes. Mostly actions and components I suppose but also in other places.&lt;/p&gt;
&lt;p&gt;Now when you want to test those methods that include a static call like this you will notice that you need to bootstrap a lot of symfony and Doctrine. Many times you will also need to open a database connection. But the method you want to test only calls to database related methods.&lt;/p&gt;
&lt;p&gt;I would like to be able to mock all these database related methods in order to optimise execution speed of my unit tests. However you can not mock static methods (with PHP3.5 and PHPUnit 3.5 you will be able to) which means that you need to connect the database.&lt;/p&gt;
&lt;p&gt;This may all sound a bit loopy but I just spend several hours optimising unit tests replacing calls to Doctrine_Core::getTable(&amp;#8216;BarFoo&amp;#8217;) with new BarFooTable().&lt;/p&gt;


&lt;div class=&quot;shr-bookmarks shr-bookmarks-expand shr-bookmarks-bg-shr&quot;&gt;
&lt;ul class=&quot;socials&quot;&gt;
		&lt;li class=&quot;shr-delicious&quot;&gt;
			&lt;a href=&quot;http://delicious.com/post?url=http://test.ical.ly/2010/08/27/why-doctrine_core-gettable-is-not-such-a-good-idea-when-phpunit-testing-a-symfony-plugin/&amp;title=Why+Doctrine_Core%3A%3AgetTable%28%27BarFoo%27%29+is+not+such+a+good+idea..+when+PHPUnit+testing+a+symfony+plugin&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on del.icio.us&quot;&gt;Share this on del.icio.us&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-linkedin&quot;&gt;
			&lt;a href=&quot;http://www.linkedin.com/shareArticle?mini=true&amp;url=http://test.ical.ly/2010/08/27/why-doctrine_core-gettable-is-not-such-a-good-idea-when-phpunit-testing-a-symfony-plugin/&amp;title=Why+Doctrine_Core%3A%3AgetTable%28%27BarFoo%27%29+is+not+such+a+good+idea..+when+PHPUnit+testing+a+symfony+plugin&amp;summary=If%20you%20have%20a%20look%20at%20the%20symfony%20and%20Doctrine%20documentation%20you%20will%20notice%20that%20whenever%20you%20want%20to%20get%20the%20table%20object%20for%20a%20model%20you%20will%20call%20Doctrine_Core%3A%3AgetTable%28%27ModelName%27%29.Apparently%20this%20is%20considered%20a%20best%20practice%20however%20I%20came%20to%20thing%20quite%20the%20opposite.As%20you%20probably%20know%20I%20a&amp;source=test.ical.ly&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on LinkedIn&quot;&gt;Share this on LinkedIn&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-mail&quot;&gt;
			&lt;a href=&quot;mailto:?subject=%22Why%20Doctrine_Core%3A%3AgetTable%28%27BarFoo%27%29%20is%20not%20such%20a%20good%20idea..%20when%20PHPUnit%20testing%20a%20symfony%20plugin%22&amp;body=Link: http://test.ical.ly/2010/08/27/why-doctrine_core-gettable-is-not-such-a-good-idea-when-phpunit-testing-a-symfony-plugin/ (sent via shareaholic)%0D%0A%0D%0A----%0D%0A If%20you%20have%20a%20look%20at%20the%20symfony%20and%20Doctrine%20documentation%20you%20will%20notice%20that%20whenever%20you%20want%20to%20get%20the%20table%20object%20for%20a%20model%20you%20will%20call%20Doctrine_Core%3A%3AgetTable%28%27ModelName%27%29.Apparently%20this%20is%20considered%20a%20best%20practice%20however%20I%20came%20to%20thing%20quite%20the%20opposite.As%20you%20probably%20know%20I%20a&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Email this to a friend?&quot;&gt;Email this to a friend?&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-misterwong&quot;&gt;
			&lt;a href=&quot;http://www.mister-wong.com/addurl/?bm_url=http://test.ical.ly/2010/08/27/why-doctrine_core-gettable-is-not-such-a-good-idea-when-phpunit-testing-a-symfony-plugin/&amp;bm_description=Why+Doctrine_Core%3A%3AgetTable%28%27BarFoo%27%29+is+not+such+a+good+idea..+when+PHPUnit+testing+a+symfony+plugin&amp;plugin=sexybookmarks&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Add this to Mister Wong&quot;&gt;Add this to Mister Wong&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-netvibes&quot;&gt;
			&lt;a href=&quot;http://www.netvibes.com/share?title=Why+Doctrine_Core%3A%3AgetTable%28%27BarFoo%27%29+is+not+such+a+good+idea..+when+PHPUnit+testing+a+symfony+plugin&amp;url=http://test.ical.ly/2010/08/27/why-doctrine_core-gettable-is-not-such-a-good-idea-when-phpunit-testing-a-symfony-plugin/&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Submit this to Netvibes&quot;&gt;Submit this to Netvibes&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-reddit&quot;&gt;
			&lt;a href=&quot;http://reddit.com/submit?url=http://test.ical.ly/2010/08/27/why-doctrine_core-gettable-is-not-such-a-good-idea-when-phpunit-testing-a-symfony-plugin/&amp;title=Why+Doctrine_Core%3A%3AgetTable%28%27BarFoo%27%29+is+not+such+a+good+idea..+when+PHPUnit+testing+a+symfony+plugin&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on Reddit&quot;&gt;Share this on Reddit&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-stumbleupon&quot;&gt;
			&lt;a href=&quot;http://www.stumbleupon.com/submit?url=http://test.ical.ly/2010/08/27/why-doctrine_core-gettable-is-not-such-a-good-idea-when-phpunit-testing-a-symfony-plugin/&amp;title=Why+Doctrine_Core%3A%3AgetTable%28%27BarFoo%27%29+is+not+such+a+good+idea..+when+PHPUnit+testing+a+symfony+plugin&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Stumble upon something good? Share it on StumbleUpon&quot;&gt;Stumble upon something good? Share it on StumbleUpon&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-twitter&quot;&gt;
			&lt;a href=&quot;http://twitter.com/home?status=Why+Doctrine_Core%3A%3AgetTable%28%27BarFoo%27%29+is+not+such+a+good+idea..+when+PHPUnit+tes%5B..%5D+-+http://bit.ly/9j04vh&amp;source=shareaholic&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Tweet This!&quot;&gt;Tweet This!&lt;/a&gt;
		&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;/div&gt;
&lt;/div&gt;</content>
		<author>
			<name>Christian</name>
			<uri>http://test.ical.ly</uri>
		</author>
		<source>
			<title type="html">test.ical.ly &#187; phpUnit</title>
			<subtitle type="html">getting PHP by the balls</subtitle>
			<link rel="self" href="http://test.ical.ly/tags/phpunit/feed/atom/"/>
			<id>http://test.ical.ly/feed/atom/</id>
			<updated>2010-09-01T00:00:27+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Applying best practices for PHPUnit testing symfony plugins</title>
		<link href="http://test.ical.ly/2010/08/26/applying-best-practices-for-phpunit-testing-symfony-plugins/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=applying-best-practices-for-phpunit-testing-symfony-plugins"/>
		<id>http://test.ical.ly/?p=1329</id>
		<updated>2010-08-25T18:11:16+00:00</updated>
		<content type="html">&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/08/best-practice.jpg&quot;&gt;&lt;img class=&quot;alignleft size-medium wp-image-1330&quot; title=&quot;best-practice&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/08/best-practice-300x199.jpg&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;199&quot; /&gt;&lt;/a&gt;By now I have been writing quite a bit about how to utilise PHPUnit when developing symfony plugins. But symfony is of course still bundled with lime so before starting right away every plugin needs to be prepared with small changes like adjusting the bootstrap.&lt;/p&gt;
&lt;p&gt;And because all these little changes have to be repeated over and over again for every plugin you start they tend to get tedious.&lt;/p&gt;
&lt;p&gt;But I&amp;#8217;ve got an idea! &lt;img src=&quot;http://test.ical.ly/wp-includes/images/smilies/icon_wink.gif&quot; alt=&quot;;)&quot; class=&quot;wp-smiley&quot; /&gt; &lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1329&quot;&gt;&lt;/span&gt;Well credit where credit is due: it was actually Stefan Koopmanschap (skoop) who initially gave me the idea of putting my findings and best practices into a plugin.&lt;/p&gt;
&lt;p&gt;So what is to be expected?&lt;/p&gt;
&lt;p&gt;Well so far I plan the following three features:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A symfony task to change the default test bootstrap to work with PHPUnit&lt;/li&gt;
&lt;li&gt;A symfony task &#160;to create a best practice phpunit.xml.dist&lt;/li&gt;
&lt;li&gt;A symfony task to create skeleton test cases for classes in your project&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Of course the plugin itself will be PHPUnit tested (eating my own dog food).&lt;/p&gt;
&lt;p&gt;What would you like to see implemented? Feel free to &lt;a href=&quot;http://www.quora.com/What-would-you-like-to-be-automated-to-help-you-with-PHPUnit-testing-when-developing-symfony-plugins&quot; target=&quot;_blank&quot;&gt;comment on quora&lt;/a&gt;.&lt;/p&gt;


&lt;div class=&quot;shr-bookmarks shr-bookmarks-expand shr-bookmarks-bg-shr&quot;&gt;
&lt;ul class=&quot;socials&quot;&gt;
		&lt;li class=&quot;shr-delicious&quot;&gt;
			&lt;a href=&quot;http://delicious.com/post?url=http://test.ical.ly/2010/08/26/applying-best-practices-for-phpunit-testing-symfony-plugins/&amp;title=Applying+best+practices+for+PHPUnit+testing+symfony+plugins&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on del.icio.us&quot;&gt;Share this on del.icio.us&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-linkedin&quot;&gt;
			&lt;a href=&quot;http://www.linkedin.com/shareArticle?mini=true&amp;url=http://test.ical.ly/2010/08/26/applying-best-practices-for-phpunit-testing-symfony-plugins/&amp;title=Applying+best+practices+for+PHPUnit+testing+symfony+plugins&amp;summary=By%20now%20I%20have%20been%20writing%20quite%20a%20bit%20about%20how%20to%20utilise%20PHPUnit%20when%20developing%20symfony%20plugins.%20But%20symfony%20is%20of%20course%20still%20bundled%20with%20lime%20so%20before%20starting%20right%20away%20every%20plugin%20needs%20to%20be%20prepared%20with%20small%20changes%20like%20adjusting%20the%20bootstrap.And%20because%20all%20these%20little%20changes%20h&amp;source=test.ical.ly&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on LinkedIn&quot;&gt;Share this on LinkedIn&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-mail&quot;&gt;
			&lt;a href=&quot;mailto:?subject=%22Applying%20best%20practices%20for%20PHPUnit%20testing%20symfony%20plugins%22&amp;body=Link: http://test.ical.ly/2010/08/26/applying-best-practices-for-phpunit-testing-symfony-plugins/ (sent via shareaholic)%0D%0A%0D%0A----%0D%0A By%20now%20I%20have%20been%20writing%20quite%20a%20bit%20about%20how%20to%20utilise%20PHPUnit%20when%20developing%20symfony%20plugins.%20But%20symfony%20is%20of%20course%20still%20bundled%20with%20lime%20so%20before%20starting%20right%20away%20every%20plugin%20needs%20to%20be%20prepared%20with%20small%20changes%20like%20adjusting%20the%20bootstrap.And%20because%20all%20these%20little%20changes%20h&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Email this to a friend?&quot;&gt;Email this to a friend?&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-misterwong&quot;&gt;
			&lt;a href=&quot;http://www.mister-wong.com/addurl/?bm_url=http://test.ical.ly/2010/08/26/applying-best-practices-for-phpunit-testing-symfony-plugins/&amp;bm_description=Applying+best+practices+for+PHPUnit+testing+symfony+plugins&amp;plugin=sexybookmarks&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Add this to Mister Wong&quot;&gt;Add this to Mister Wong&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-netvibes&quot;&gt;
			&lt;a href=&quot;http://www.netvibes.com/share?title=Applying+best+practices+for+PHPUnit+testing+symfony+plugins&amp;url=http://test.ical.ly/2010/08/26/applying-best-practices-for-phpunit-testing-symfony-plugins/&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Submit this to Netvibes&quot;&gt;Submit this to Netvibes&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-reddit&quot;&gt;
			&lt;a href=&quot;http://reddit.com/submit?url=http://test.ical.ly/2010/08/26/applying-best-practices-for-phpunit-testing-symfony-plugins/&amp;title=Applying+best+practices+for+PHPUnit+testing+symfony+plugins&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on Reddit&quot;&gt;Share this on Reddit&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-stumbleupon&quot;&gt;
			&lt;a href=&quot;http://www.stumbleupon.com/submit?url=http://test.ical.ly/2010/08/26/applying-best-practices-for-phpunit-testing-symfony-plugins/&amp;title=Applying+best+practices+for+PHPUnit+testing+symfony+plugins&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Stumble upon something good? Share it on StumbleUpon&quot;&gt;Stumble upon something good? Share it on StumbleUpon&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-twitter&quot;&gt;
			&lt;a href=&quot;http://twitter.com/home?status=Applying+best+practices+for+PHPUnit+testing+symfony+plugins+-+http://bit.ly/bWTYIu&amp;source=shareaholic&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Tweet This!&quot;&gt;Tweet This!&lt;/a&gt;
		&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;/div&gt;
&lt;/div&gt;</content>
		<author>
			<name>Christian</name>
			<uri>http://test.ical.ly</uri>
		</author>
		<source>
			<title type="html">test.ical.ly &#187; phpUnit</title>
			<subtitle type="html">getting PHP by the balls</subtitle>
			<link rel="self" href="http://test.ical.ly/tags/phpunit/feed/atom/"/>
			<id>http://test.ical.ly/feed/atom/</id>
			<updated>2010-09-01T00:00:27+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">[Best practice] How to ship PHPUnit configuration</title>
		<link href="http://test.ical.ly/2010/08/24/best-practice-how-to-ship-phpunit-configuration/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=best-practice-how-to-ship-phpunit-configuration"/>
		<id>http://test.ical.ly/?p=1317</id>
		<updated>2010-08-23T16:07:10+00:00</updated>
		<content type="html">&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/08/phpunit.xml_.jpg&quot;&gt;&lt;img class=&quot;alignleft size-medium wp-image-1318&quot; title=&quot;phpunit.xml&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/08/phpunit.xml_-300x219.jpg&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;219&quot; /&gt;&lt;/a&gt;PHPUnit offers quite a lot options to be set as arguments on the commandline. However this is tedious when typing over and over again.&lt;/p&gt;
&lt;p&gt;For this reason you can create an &lt;a href=&quot;http://www.phpunit.de/manual/current/en/appendixes.configuration.html&quot; target=&quot;_blank&quot;&gt;XML configuration file &lt;/a&gt;&lt;code&gt;&lt;a href=&quot;http://www.phpunit.de/manual/current/en/appendixes.configuration.html&quot; target=&quot;_blank&quot;&gt;phpunit.xml&lt;/a&gt;&lt;/code&gt; that will automatically be used by the phpunit binary.&lt;/p&gt;
&lt;p&gt;Now you may want to include this configuration file in your projects sourcecode to be used by all participating developers and your continuous integration server. But how?&lt;/p&gt;
&lt;h2&gt;&lt;span id=&quot;more-1317&quot;&gt;&lt;/span&gt;Well, you could just commit the &lt;code&gt;phpunit.xml&lt;/code&gt; to you repository right?&lt;/h2&gt;
&lt;p&gt;Well, yes. But then all developers who want to checkout and work on your project will have to use these settings or going through the trouble of maintaining local changes to the configuration or specifying a different one using the commandline.&lt;/p&gt;
&lt;h2&gt;No! Use &lt;code&gt;phpunit.xml.dist&lt;/code&gt; instead.&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://github.com/caefer/StreamHitching/commit/e1a6cef49ea6466403e3aea533728e04139e5d80&quot; target=&quot;_blank&quot;&gt;Sebastian made me aware of this&lt;/a&gt; and he is right. If you provide a &lt;code&gt;phpunit.xml.dist&lt;/code&gt;(ribution) instead then every developer can chose whether to use your configuration or his/her own.&lt;/p&gt;
&lt;p&gt;It is also wise to ignore the real &lt;code&gt;phpunit.xml&lt;/code&gt; for your repository using &lt;code&gt;.gitignore&lt;/code&gt; or &lt;code&gt;svn:ignore&lt;/code&gt; or similar. This way everybody can use the settings he/she wants without forcing them onto others.&lt;/p&gt;
&lt;h2&gt;How can my continuous integration server use the config?&lt;/h2&gt;
&lt;p&gt;Simple! the phpunit binary is clever enough to use any &lt;code&gt;phpunit.xml.dist&lt;/code&gt; file if no &lt;code&gt;phpunit.xml&lt;/code&gt; is available. &lt;img src=&quot;http://test.ical.ly/wp-includes/images/smilies/icon_smile.gif&quot; alt=&quot;:)&quot; class=&quot;wp-smiley&quot; /&gt; &lt;/p&gt;


&lt;div class=&quot;shr-bookmarks shr-bookmarks-expand shr-bookmarks-bg-shr&quot;&gt;
&lt;ul class=&quot;socials&quot;&gt;
		&lt;li class=&quot;shr-delicious&quot;&gt;
			&lt;a href=&quot;http://delicious.com/post?url=http://test.ical.ly/2010/08/24/best-practice-how-to-ship-phpunit-configuration/&amp;title=%5BBest+practice%5D+How+to+ship+PHPUnit+configuration&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on del.icio.us&quot;&gt;Share this on del.icio.us&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-linkedin&quot;&gt;
			&lt;a href=&quot;http://www.linkedin.com/shareArticle?mini=true&amp;url=http://test.ical.ly/2010/08/24/best-practice-how-to-ship-phpunit-configuration/&amp;title=%5BBest+practice%5D+How+to+ship+PHPUnit+configuration&amp;summary=PHPUnit%20offers%20quite%20a%20lot%20options%20to%20be%20set%20as%20arguments%20on%20the%20commandline.%20However%20this%20is%20tedious%20when%20typing%20over%20and%20over%20again.%0D%0A%0D%0AFor%20this%20reason%20you%20can%20create%20an%20XML%20configuration%20file%20phpunit.xml%20that%20will%20automatically%20be%20used%20by%20the%20phpunit%20binary.%0D%0A%0D%0ANow%20you%20may%20want%20to%20include%20this%20co&amp;source=test.ical.ly&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on LinkedIn&quot;&gt;Share this on LinkedIn&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-mail&quot;&gt;
			&lt;a href=&quot;mailto:?subject=%22%5BBest%20practice%5D%20How%20to%20ship%20PHPUnit%20configuration%22&amp;body=Link: http://test.ical.ly/2010/08/24/best-practice-how-to-ship-phpunit-configuration/ (sent via shareaholic)%0D%0A%0D%0A----%0D%0A PHPUnit%20offers%20quite%20a%20lot%20options%20to%20be%20set%20as%20arguments%20on%20the%20commandline.%20However%20this%20is%20tedious%20when%20typing%20over%20and%20over%20again.%0D%0A%0D%0AFor%20this%20reason%20you%20can%20create%20an%20XML%20configuration%20file%20phpunit.xml%20that%20will%20automatically%20be%20used%20by%20the%20phpunit%20binary.%0D%0A%0D%0ANow%20you%20may%20want%20to%20include%20this%20co&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Email this to a friend?&quot;&gt;Email this to a friend?&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-misterwong&quot;&gt;
			&lt;a href=&quot;http://www.mister-wong.com/addurl/?bm_url=http://test.ical.ly/2010/08/24/best-practice-how-to-ship-phpunit-configuration/&amp;bm_description=%5BBest+practice%5D+How+to+ship+PHPUnit+configuration&amp;plugin=sexybookmarks&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Add this to Mister Wong&quot;&gt;Add this to Mister Wong&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-netvibes&quot;&gt;
			&lt;a href=&quot;http://www.netvibes.com/share?title=%5BBest+practice%5D+How+to+ship+PHPUnit+configuration&amp;url=http://test.ical.ly/2010/08/24/best-practice-how-to-ship-phpunit-configuration/&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Submit this to Netvibes&quot;&gt;Submit this to Netvibes&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-reddit&quot;&gt;
			&lt;a href=&quot;http://reddit.com/submit?url=http://test.ical.ly/2010/08/24/best-practice-how-to-ship-phpunit-configuration/&amp;title=%5BBest+practice%5D+How+to+ship+PHPUnit+configuration&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on Reddit&quot;&gt;Share this on Reddit&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-stumbleupon&quot;&gt;
			&lt;a href=&quot;http://www.stumbleupon.com/submit?url=http://test.ical.ly/2010/08/24/best-practice-how-to-ship-phpunit-configuration/&amp;title=%5BBest+practice%5D+How+to+ship+PHPUnit+configuration&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Stumble upon something good? Share it on StumbleUpon&quot;&gt;Stumble upon something good? Share it on StumbleUpon&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-twitter&quot;&gt;
			&lt;a href=&quot;http://twitter.com/home?status=%5BBest+practice%5D+How+to+ship+PHPUnit+configuration+-+http://bit.ly/bemIjW&amp;source=shareaholic&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Tweet This!&quot;&gt;Tweet This!&lt;/a&gt;
		&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;/div&gt;
&lt;/div&gt;</content>
		<author>
			<name>Christian</name>
			<uri>http://test.ical.ly</uri>
		</author>
		<source>
			<title type="html">test.ical.ly &#187; phpUnit</title>
			<subtitle type="html">getting PHP by the balls</subtitle>
			<link rel="self" href="http://test.ical.ly/tags/phpunit/feed/atom/"/>
			<id>http://test.ical.ly/feed/atom/</id>
			<updated>2010-09-01T00:00:27+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Setting up Continuous Integration for a symfony plugin using Hudson and Sebastian Bergmanns (PHPUnit) Template for Hudson Jobs for PHP Projects</title>
		<link href="http://test.ical.ly/2010/08/23/setting-up-continuous-integration-for-a-symfony-plugin-using-hudson-and-sebastian-bergmanns-phpunit-template-for-hudson-jobs-for-php-projects/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=setting-up-continuous-integration-for-a-symfony-plugin-using-hudson-and-sebastian-bergmanns-phpunit-template-for-hudson-jobs-for-php-projects"/>
		<id>http://test.ical.ly/?p=1305</id>
		<updated>2010-08-22T19:35:32+00:00</updated>
		<content type="html">&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/08/installing.jpg&quot;&gt;&lt;img class=&quot;alignleft size-medium wp-image-1306&quot; title=&quot;installing&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/08/installing-300x200.jpg&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;200&quot; /&gt;&lt;/a&gt;I must admit that I have been lazy with my efforts on continuous integration lately. Eventually my server crashed unnoticed and I didn&amp;#8217;t get any emails about broken builds anymore and by now I think I&amp;#8217;ve stacked up some work to do.&lt;/p&gt;
&lt;p&gt;First of course I&amp;#8217;ve got to get my CI server up and running again, that&amp;#8217;s why I installed Hudson again.&lt;/p&gt;
&lt;p&gt;But there is room for improvement too. Sebastian Bergmann of PHPUnit fame spent some time on a &lt;a href=&quot;http://github.com/sebastianbergmann/php-hudson-template&quot; target=&quot;_blank&quot;&gt;template Hudson job for PHP projects&lt;/a&gt; that includes much more than PHPUnit. So I decided to use that!&lt;/p&gt;
&lt;h2&gt;&lt;span id=&quot;more-1305&quot;&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h2&gt;Goal&lt;/h2&gt;
&lt;p&gt;What I want to achieve is to setup a project for my symfony plugin &lt;a href=&quot;http://www.symfony-project.org/plugins/sfImageTransformExtraPlugin&quot; target=&quot;_blank&quot;&gt;sfImageTransformExtraPlugin&lt;/a&gt; using the Sebastians&#160;template.&lt;/p&gt;
&lt;h2&gt;Prerequesites&lt;/h2&gt;
&lt;p&gt;I am assuming that you already have a working Hudson installation and the following plugins installed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Checkstyle (for processing PHP_CodeSniffer logfiles in Checkstyle format)&lt;/li&gt;
&lt;li&gt;DRY (for processing phpcpd logfiles in PMD-CPD format)&lt;/li&gt;
&lt;li&gt;HTML Publisher (for publishing the PHPUnit code coverage report, for instance)&lt;/li&gt;
&lt;li&gt;JDepend (for processing PHP_Depend logfiles in JDepend format)&lt;/li&gt;
&lt;li&gt;PMD (for processing phpmd logfiles in PMD format)&lt;/li&gt;
&lt;li&gt;Template Project (for using php-hudson-template as a template for Hudson jobs)&lt;/li&gt;
&lt;li&gt;Violations (for processing various logfiles)&lt;/li&gt;
&lt;li&gt;xUnit (for processing PHPUnit logfiles in JUnit format)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Setting up the template job&lt;/h2&gt;
&lt;p&gt;Just as described in the README on GitHub we just checkout the project in to our Hudson jobs folder.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;sh&quot;&gt;$ cd /home/of/hudson/jobs
$ git clone git://github.com/sebastianbergmann/php-hudson-template.git&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And then we have to restart Hudson to take notice of this new job.&lt;/p&gt;
&lt;p&gt;The job itself is disabled as it has no subject.&lt;/p&gt;
&lt;h2&gt;Setting up the real job&lt;/h2&gt;
&lt;p&gt;So what I want to do is to checkout the current development version of my symfony plugin from GitHub. I also have to checkout it dependencies which are symfony itself and sfImageTransformPlugin which both are available only via Subversion.&lt;/p&gt;
&lt;p&gt;I start by adding a new &amp;#8220;free-style software project&amp;#8221; job with the name &amp;#8220;sfImageTransformExtraPlugin&amp;#8221;.&lt;/p&gt;
&lt;p&gt;First I configure the GitHub source and under the advanced options I configure it to be checked out into a local subdirectory &amp;#8220;sfImageTransformExtraPlugin&amp;#8221;.&lt;/p&gt;
&lt;p&gt;Next I add a build step &amp;#8220;Invoke Ant&amp;#8221; and under advanced options I point it to the build.xml at &amp;#8220;sfImageTransformExtraPlugin/build.xml&amp;#8221;.&lt;/p&gt;
&lt;p&gt;Last thing to configure is to &amp;#8220;Use publishers from another project&amp;#8221; and I enter &amp;#8220;php-hudson-template&amp;#8221; as the template project.&lt;/p&gt;
&lt;p&gt;And that all you have to do to setup the project in Hudson.&lt;/p&gt;
&lt;p&gt;But of course that&amp;#8217;s not all. Two produce all the reports that the template should process and to checkout and update the dependencies we need two more configuration files which are both part of the plugin.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;This is more or less a copy of the example from Sebastians GitHub Page with soem slight modifications.&lt;/p&gt;
&lt;p&gt;The first target &amp;#8220;update&amp;#8221; will check out the dependencies from symfonys Subversion repositories in parallel to the plugin itself. The plugin is configured to assume symfony and sfImageTransformPlugin at these locations.&lt;/p&gt;
&lt;p&gt;All artifacts such as coverage reports and metrics will be written to a directory &amp;#8220;build&amp;#8221; which also lies in parallel to the plugin source. All together will produce a directory structure like this.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;sh&quot;&gt;/path/to/hudson/jobs/sfImageTransformExtraPlugin/build/
/path/to/hudson/jobs/sfImageTransformExtraPlugin/sfImageTransformExtraPlugin/
/path/to/hudson/jobs/sfImageTransformExtraPlugin/sfImageTransformPlugin/
/path/to/hudson/jobs/sfImageTransformExtraPlugin/symfony/&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But not all reports that are expected by the template are being produced by this build.xml. The PHPUnit specific reports are configured in the phpunit.xml file.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Adjust these two configuration files for your plugin to your needs and you&amp;#8217;re ready to go.&lt;/p&gt;
&lt;p&gt;In the following weeks I will write some posts explaining all the results you can now see in your Hudson installation (or in &lt;a href=&quot;http://automat.ical.ly/&quot; target=&quot;_blank&quot;&gt;mine&lt;/a&gt;).&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This template makes setting up Hudson for PHP development so much easier! Great thanks to Sebastian for his awesome work!&lt;/p&gt;


&lt;div class=&quot;shr-bookmarks shr-bookmarks-expand shr-bookmarks-bg-shr&quot;&gt;
&lt;ul class=&quot;socials&quot;&gt;
		&lt;li class=&quot;shr-delicious&quot;&gt;
			&lt;a href=&quot;http://delicious.com/post?url=http://test.ical.ly/2010/08/23/setting-up-continuous-integration-for-a-symfony-plugin-using-hudson-and-sebastian-bergmanns-phpunit-template-for-hudson-jobs-for-php-projects/&amp;title=Setting+up+Continuous+Integration+for+a+symfony+plugin+using+Hudson+and+Sebastian+Bergmanns+%28PHPUnit%29+Template+for+Hudson+Jobs+for+PHP+Projects&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on del.icio.us&quot;&gt;Share this on del.icio.us&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-linkedin&quot;&gt;
			&lt;a href=&quot;http://www.linkedin.com/shareArticle?mini=true&amp;url=http://test.ical.ly/2010/08/23/setting-up-continuous-integration-for-a-symfony-plugin-using-hudson-and-sebastian-bergmanns-phpunit-template-for-hudson-jobs-for-php-projects/&amp;title=Setting+up+Continuous+Integration+for+a+symfony+plugin+using+Hudson+and+Sebastian+Bergmanns+%28PHPUnit%29+Template+for+Hudson+Jobs+for+PHP+Projects&amp;summary=I%20must%20admit%20that%20I%20have%20been%20lazy%20with%20my%20efforts%20on%20continuous%20integration%20lately.%20Eventually%20my%20server%20crashed%20unnoticed%20and%20I%20didn%27t%20get%20any%20emails%20about%20broken%20builds%20anymore%20and%20by%20now%20I%20think%20I%27ve%20stacked%20up%20some%20work%20to%20do.%20First%20of%20course%20I%27ve%20got%20to%20get%20my%20CI%20server%20up%20and%20running%20again%2C%20t&amp;source=test.ical.ly&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on LinkedIn&quot;&gt;Share this on LinkedIn&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-mail&quot;&gt;
			&lt;a href=&quot;mailto:?subject=%22Setting%20up%20Continuous%20Integration%20for%20a%20symfony%20plugin%20using%20Hudson%20and%20Sebastian%20Bergmanns%20%28PHPUnit%29%20Template%20for%20Hudson%20Jobs%20for%20PHP%20Projects%22&amp;body=Link: http://test.ical.ly/2010/08/23/setting-up-continuous-integration-for-a-symfony-plugin-using-hudson-and-sebastian-bergmanns-phpunit-template-for-hudson-jobs-for-php-projects/ (sent via shareaholic)%0D%0A%0D%0A----%0D%0A I%20must%20admit%20that%20I%20have%20been%20lazy%20with%20my%20efforts%20on%20continuous%20integration%20lately.%20Eventually%20my%20server%20crashed%20unnoticed%20and%20I%20didn%27t%20get%20any%20emails%20about%20broken%20builds%20anymore%20and%20by%20now%20I%20think%20I%27ve%20stacked%20up%20some%20work%20to%20do.%20First%20of%20course%20I%27ve%20got%20to%20get%20my%20CI%20server%20up%20and%20running%20again%2C%20t&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Email this to a friend?&quot;&gt;Email this to a friend?&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-misterwong&quot;&gt;
			&lt;a href=&quot;http://www.mister-wong.com/addurl/?bm_url=http://test.ical.ly/2010/08/23/setting-up-continuous-integration-for-a-symfony-plugin-using-hudson-and-sebastian-bergmanns-phpunit-template-for-hudson-jobs-for-php-projects/&amp;bm_description=Setting+up+Continuous+Integration+for+a+symfony+plugin+using+Hudson+and+Sebastian+Bergmanns+%28PHPUnit%29+Template+for+Hudson+Jobs+for+PHP+Projects&amp;plugin=sexybookmarks&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Add this to Mister Wong&quot;&gt;Add this to Mister Wong&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-netvibes&quot;&gt;
			&lt;a href=&quot;http://www.netvibes.com/share?title=Setting+up+Continuous+Integration+for+a+symfony+plugin+using+Hudson+and+Sebastian+Bergmanns+%28PHPUnit%29+Template+for+Hudson+Jobs+for+PHP+Projects&amp;url=http://test.ical.ly/2010/08/23/setting-up-continuous-integration-for-a-symfony-plugin-using-hudson-and-sebastian-bergmanns-phpunit-template-for-hudson-jobs-for-php-projects/&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Submit this to Netvibes&quot;&gt;Submit this to Netvibes&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-reddit&quot;&gt;
			&lt;a href=&quot;http://reddit.com/submit?url=http://test.ical.ly/2010/08/23/setting-up-continuous-integration-for-a-symfony-plugin-using-hudson-and-sebastian-bergmanns-phpunit-template-for-hudson-jobs-for-php-projects/&amp;title=Setting+up+Continuous+Integration+for+a+symfony+plugin+using+Hudson+and+Sebastian+Bergmanns+%28PHPUnit%29+Template+for+Hudson+Jobs+for+PHP+Projects&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on Reddit&quot;&gt;Share this on Reddit&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-stumbleupon&quot;&gt;
			&lt;a href=&quot;http://www.stumbleupon.com/submit?url=http://test.ical.ly/2010/08/23/setting-up-continuous-integration-for-a-symfony-plugin-using-hudson-and-sebastian-bergmanns-phpunit-template-for-hudson-jobs-for-php-projects/&amp;title=Setting+up+Continuous+Integration+for+a+symfony+plugin+using+Hudson+and+Sebastian+Bergmanns+%28PHPUnit%29+Template+for+Hudson+Jobs+for+PHP+Projects&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Stumble upon something good? Share it on StumbleUpon&quot;&gt;Stumble upon something good? Share it on StumbleUpon&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-twitter&quot;&gt;
			&lt;a href=&quot;http://twitter.com/home?status=Setting+up+Continuous+Integration+for+a+symfony+plugin+using+Hudson+and+Sebastia%5B..%5D+-+http://bit.ly/bLuAos&amp;source=shareaholic&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Tweet This!&quot;&gt;Tweet This!&lt;/a&gt;
		&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;/div&gt;
&lt;/div&gt;</content>
		<author>
			<name>Christian</name>
			<uri>http://test.ical.ly</uri>
		</author>
		<source>
			<title type="html">test.ical.ly &#187; phpUnit</title>
			<subtitle type="html">getting PHP by the balls</subtitle>
			<link rel="self" href="http://test.ical.ly/tags/phpunit/feed/atom/"/>
			<id>http://test.ical.ly/feed/atom/</id>
			<updated>2010-09-01T00:00:27+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">PHPUnit 3.5: Less $this Required</title>
		<link href="http://sebastian-bergmann.de/archives/896-PHPUnit-3.5-Less-this-Required.html"/>
		<id>http://sebastian-bergmann.de/archives/896-guid.html</id>
		<updated>2010-08-16T13:45:00+00:00</updated>
		<content type="html">&lt;p&gt;&lt;strike&gt;&lt;strong&gt;The feature discussed below has been removed from PHPUnit due to community feedback.&lt;/strong&gt;&lt;/strike&gt;&lt;/p&gt;&lt;p&gt;Over the years, I have gotten quite a few &quot;complaints&quot; from PHPUnit users that they do not like typing &lt;code&gt;$this-&gt;&lt;/code&gt; as often as they have to:&lt;/p&gt;&lt;dl&gt;&lt;dd&gt;&lt;pre class=&quot;programlisting&quot;&gt;&lt;code&gt;&lt;span class=&quot;default&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;StackTest&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;PHPUnit_Framework_TestCase&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;testPushAndPop&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$stack&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;assertEquals&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$stack&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;array_push&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$stack&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'foo'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;assertEquals&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'foo'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$stack&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$stack&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;assertEquals&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$stack&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;assertEquals&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'foo'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;array_pop&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$stack&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;assertEquals&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$stack&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/dd&gt;&lt;/dl&gt;&lt;p&gt;As of PHPUnit 3.5, they can write test code that requires less &lt;code&gt;$this-&gt;&lt;/code&gt; statements:&lt;/p&gt;&lt;dl&gt;&lt;dd&gt;&lt;pre class=&quot;programlisting&quot;&gt;&lt;code&gt;&lt;span class=&quot;default&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;require_once&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'PHPUnit/Framework/Assert/Functions.php'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;StackTest&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;PHPUnit_Framework_TestCase&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;testPushAndPop&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$stack&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;assertEquals&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$stack&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;array_push&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$stack&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'foo'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;assertEquals&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'foo'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$stack&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$stack&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;assertEquals&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$stack&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;assertEquals&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'foo'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;array_pop&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$stack&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;assertEquals&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$stack&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/dd&gt;&lt;/dl&gt;&lt;p&gt;Here's hoping that this makes some people happy :-)&lt;/p&gt;</content>
		<author>
			<name>Sebastian Bergmann</name>
			<email>nospam@example.com</email>
			<uri>http://sebastian-bergmann.de/</uri>
		</author>
		<source>
			<title type="html">Sebastian Bergmann - PHPUnit</title>
			<link rel="self" href="http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss"/>
			<id>http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss</id>
			<updated>2010-08-19T08:00:26+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">GTAC 2010</title>
		<link href="http://sebastian-bergmann.de/archives/893-GTAC-2010.html"/>
		<id>http://sebastian-bergmann.de/archives/893-guid.html</id>
		<updated>2010-07-23T13:20:35+00:00</updated>
		<content type="html">&lt;p&gt;I have been invited to attend the &lt;a href=&quot;http://www.gtac.biz/&quot;&gt;5th Annual Google Test Automation Conference&lt;/a&gt;, better known as GTAC, in Hyderabad, India in October. I am very much looking forward to &lt;em&gt;discuss cutting edge challenges in test automation and evaluate potential solutions&lt;/em&gt;, especially with this year's focus on testability.&lt;/p&gt;&lt;p&gt;Another thing I like about this year's GTAC is that the participants are responsible for selecting the presentations for the conference. Here is my submission:&lt;/p&gt;&lt;dl&gt;&lt;dd&gt;&lt;h3&gt;Challenges in Unit Testing PHP Applications&lt;/h3&gt;&lt;p&gt;According to TIOBE, PHP is the most popular programming language after C/C++ and Java. The language has made strong inroads into large-scale, business-critical Web systems. In the six years since the release of PHP 5 -- which not only kickstarted the development of PHP-based frameworks for Web development but also the development of tools for dynamic and static testing techniques -- the PHP community as a whole has developed an increasing interest in developing software that delivers the best possible quality.&lt;/p&gt;&lt;p&gt;When PHP developers start to write unit tests they rarely find themselves without any constraints that are imposed by prior work of less than optimal quality. It is a well-known fact that writing unit tests for legacy code is hard. In the case of PHP it can be even harder: the legacy code has not only been written without testability in mind, but it may have been written for earlier versions of PHP that encouraged practices that make the code next to impossible to unit test.&lt;/p&gt;&lt;p&gt;PHPUnit, the de-facto standard framework for unit-testing PHP code, has some unique features not found in other xUnit test frameworks that allow the testing of untestable code. While developers should not use these features (as they are not required when writing tests for testable code), these features ease the pain of writing tests for legacy code and thus help developers get started with unit testing before they refactor the code for testability.&lt;/p&gt;&lt;p&gt;This session, presented by the creator of PHPUnit, highlights the challenges developers are facing when unit testing legacy PHP code. Some of these challenges will be familiar to developers that use other programming languages such as Java but they will see a new perspective on the problem and different approaches to solve it.&lt;/p&gt;&lt;/dd&gt;&lt;/dl&gt;&lt;p&gt;Although I am hoping, of course, that my submission will be accepted by my peers, I know that GTAC will be valuable for me even if I do not get to present: the &quot;hallway track&quot; of GTAC 2008 was amazing.&lt;/p&gt;</content>
		<author>
			<name>Sebastian Bergmann</name>
			<email>nospam@example.com</email>
			<uri>http://sebastian-bergmann.de/</uri>
		</author>
		<source>
			<title type="html">Sebastian Bergmann - PHPUnit</title>
			<link rel="self" href="http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss"/>
			<id>http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss</id>
			<updated>2010-08-19T08:00:26+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">PHPUnit 3.5: Refactoring to Components</title>
		<link href="http://sebastian-bergmann.de/archives/892-PHPUnit-3.5-Refactoring-to-Components.html"/>
		<id>http://sebastian-bergmann.de/archives/892-guid.html</id>
		<updated>2010-07-23T12:00:00+00:00</updated>
		<content type="html">&lt;p&gt;When you look at the list of changes for PHPUnit 3.5, you will see that many of them deal with refactoring to components. Here is an overview of these new components:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://github.com/sebastianbergmann/php-code-coverage&quot;&gt;PHP_CodeCoverage&lt;/a&gt;&lt;p&gt;The collection, processing, and rendering of code coverage information has been factored out into a separate component. A bit more information can be found &lt;a href=&quot;http://sebastian-bergmann.de/archives/886-Code-Coverage-Dashboard.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://github.com/sebastianbergmann/phpunit-mock-objects&quot;&gt;PHPUnit_MockObject&lt;/a&gt;&lt;p&gt;The functionality to automatically generate an object that can act as a test double for a specified original class has been factored out into a separate component. Do not worry, &lt;code&gt;getMock()&lt;/code&gt; and related methods will work just as they did in previous versions of PHPUnit. The refactoring, however, makes the usage of other mock object libraries (such as &lt;a href=&quot;http://github.com/padraic/mockery&quot;&gt;Mockery&lt;/a&gt; or &lt;a href=&quot;http://github.com/mlively/Phake&quot;&gt;Phake&lt;/a&gt;, for instance) easier.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://github.com/sebastianbergmann/dbunit&quot;&gt;DbUnit&lt;/a&gt;&lt;p&gt;The database testing functionality that is provided by the DbUnit extension and the respective &lt;code&gt;DatabaseTestCase&lt;/code&gt; class has been moved to a separate component. Michael Lively Jr, the author of DbUnit, is now able to make releases of the database testing extension on a release schedule that is separate from PHPUnit itself, meaning that I will be even less involved in its development than I have before.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://github.com/sebastianbergmann/phpunit-selenium&quot;&gt;PHPUnit_Selenium&lt;/a&gt;&lt;p&gt;&lt;code&gt;SeleniumTestCase&lt;/code&gt;, the &lt;a href=&quot;http://seleniumhq.org/&quot;&gt;Selenium RC&lt;/a&gt; integration for PHPUnit, has been moved to a separate component to allow a release cycle separate from PHPUnit itself.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://github.com/sebastianbergmann/php-file-iterator&quot;&gt;File_Iterator&lt;/a&gt;, &lt;a href=&quot;http://github.com/sebastianbergmann/php-timer&quot;&gt;PHP_Timer&lt;/a&gt;, &lt;a href=&quot;http://github.com/sebastianbergmann/php-text-template&quot;&gt;Text_Template&lt;/a&gt;&lt;p&gt;Utility methods to collect files and report resource usage as well as a simple templating mechanism have been moved to separate components so that they can be reused by other tools such as &lt;a href=&quot;http://github.com/mayflowergmbh/PHP_CodeBrowser&quot;&gt;phpcb&lt;/a&gt;, &lt;a href=&quot;http://pear.php.net/package/PHP_CodeSniffer&quot;&gt;phpcs&lt;/a&gt;, &lt;a href=&quot;http://github.com/sebastianbergmann/phpcpd&quot;&gt;phpcpd&lt;/a&gt;, and &lt;a href=&quot;http://pdepend.org/&quot;&gt;pdepend&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;</content>
		<author>
			<name>Sebastian Bergmann</name>
			<email>nospam@example.com</email>
			<uri>http://sebastian-bergmann.de/</uri>
		</author>
		<source>
			<title type="html">Sebastian Bergmann - PHPUnit</title>
			<link rel="self" href="http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss"/>
			<id>http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss</id>
			<updated>2010-08-19T08:00:26+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Unit testing symfony plugins with PHPUnit &amp;#8211; My session at the symfony day 2010. What do you expect?</title>
		<link href="http://test.ical.ly/2010/07/22/unit-testing-symfony-plugins-with-phpunit-my-session-at-the-symfony-day-2010-what-do-you-expect/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=unit-testing-symfony-plugins-with-phpunit-my-session-at-the-symfony-day-2010-what-do-you-expect"/>
		<id>http://test.ical.ly/?p=1179</id>
		<updated>2010-07-22T04:00:18+00:00</updated>
		<content type="html">&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/07/expectations-only-lead-to-disappointment.jpg&quot;&gt;&lt;img class=&quot;alignleft size-medium wp-image-1180&quot; title=&quot;expectations-only-lead-to-disappointment&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/07/expectations-only-lead-to-disappointment-300x300.jpg&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;300&quot; /&gt;&lt;/a&gt;I was asked to speak at the symfony day 2010 in Cologne and I happily agreed to it. &lt;a href=&quot;http://www.symfonyday.com/en/program.html#session-unit-testing-plugins&quot;&gt;My session will be about Unit testing symfony plugins with PHPUnit&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While I have a clear view what to talk about within the one hour I have I wonder what your expectations are?&lt;/p&gt;
&lt;p&gt;So instead of writing down what I want to present I ask you to have your say to give a good user experience.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What are the topics you want to hear about?&lt;/li&gt;
&lt;li&gt;What is the level of knowledge I should assume the audience to have?&lt;/li&gt;
&lt;li&gt;Do you expect a presentation or hands on examples?&lt;/li&gt;
&lt;li&gt;Theory or practice?&lt;/li&gt;
&lt;li&gt;What should I wear? &lt;img src=&quot;http://test.ical.ly/wp-includes/images/smilies/icon_wink.gif&quot; alt=&quot;;)&quot; class=&quot;wp-smiley&quot; /&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;span id=&quot;more-1179&quot;&gt;&lt;/span&gt;Comments please!&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/07/arrowdown.gif&quot;&gt;&lt;img class=&quot;alignleft size-medium wp-image-1181&quot; title=&quot;arrowdown&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/07/arrowdown-263x300.gif&quot; alt=&quot;&quot; width=&quot;205&quot; height=&quot;234&quot; /&gt;&lt;/a&gt;&lt;/p&gt;


&lt;div class=&quot;shr-bookmarks shr-bookmarks-expand shr-bookmarks-bg-shr&quot;&gt;
&lt;ul class=&quot;socials&quot;&gt;
		&lt;li class=&quot;shr-delicious&quot;&gt;
			&lt;a href=&quot;http://delicious.com/post?url=http://test.ical.ly/2010/07/22/unit-testing-symfony-plugins-with-phpunit-my-session-at-the-symfony-day-2010-what-do-you-expect/&amp;title=Unit+testing+symfony+plugins+with+PHPUnit+-+My+session+at+the+symfony+day+2010.+What+do+you+expect%3F+&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on del.icio.us&quot;&gt;Share this on del.icio.us&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-linkedin&quot;&gt;
			&lt;a href=&quot;http://www.linkedin.com/shareArticle?mini=true&amp;url=http://test.ical.ly/2010/07/22/unit-testing-symfony-plugins-with-phpunit-my-session-at-the-symfony-day-2010-what-do-you-expect/&amp;title=Unit+testing+symfony+plugins+with+PHPUnit+-+My+session+at+the+symfony+day+2010.+What+do+you+expect%3F+&amp;summary=I%20was%20asked%20to%20speak%20at%20the%20symfony%20day%202010%20in%20Cologne%20and%20I%20happily%20agreed%20to%20it.%20My%20session%20will%20be%20about%20Unit%20testing%20symfony%20plugins%20with%20PHPUnit.%0D%0A%0D%0AWhile%20I%20have%20a%20clear%20view%20what%20to%20talk%20about%20within%20the%20one%20hour%20I%20have%20I%20wonder%20what%20your%20expectations%20are%3F%0D%0A%0D%0ASo%20instead%20of%20writing%20down%20what%20I&amp;source=test.ical.ly&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on LinkedIn&quot;&gt;Share this on LinkedIn&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-mail&quot;&gt;
			&lt;a href=&quot;mailto:?subject=%22Unit%20testing%20symfony%20plugins%20with%20PHPUnit%20-%20My%20session%20at%20the%20symfony%20day%202010.%20What%20do%20you%20expect%3F%20%22&amp;body=Link: http://test.ical.ly/2010/07/22/unit-testing-symfony-plugins-with-phpunit-my-session-at-the-symfony-day-2010-what-do-you-expect/ (sent via shareaholic)%0D%0A%0D%0A----%0D%0A I%20was%20asked%20to%20speak%20at%20the%20symfony%20day%202010%20in%20Cologne%20and%20I%20happily%20agreed%20to%20it.%20My%20session%20will%20be%20about%20Unit%20testing%20symfony%20plugins%20with%20PHPUnit.%0D%0A%0D%0AWhile%20I%20have%20a%20clear%20view%20what%20to%20talk%20about%20within%20the%20one%20hour%20I%20have%20I%20wonder%20what%20your%20expectations%20are%3F%0D%0A%0D%0ASo%20instead%20of%20writing%20down%20what%20I&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Email this to a friend?&quot;&gt;Email this to a friend?&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-misterwong&quot;&gt;
			&lt;a href=&quot;http://www.mister-wong.com/addurl/?bm_url=http://test.ical.ly/2010/07/22/unit-testing-symfony-plugins-with-phpunit-my-session-at-the-symfony-day-2010-what-do-you-expect/&amp;bm_description=Unit+testing+symfony+plugins+with+PHPUnit+-+My+session+at+the+symfony+day+2010.+What+do+you+expect%3F+&amp;plugin=sexybookmarks&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Add this to Mister Wong&quot;&gt;Add this to Mister Wong&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-netvibes&quot;&gt;
			&lt;a href=&quot;http://www.netvibes.com/share?title=Unit+testing+symfony+plugins+with+PHPUnit+-+My+session+at+the+symfony+day+2010.+What+do+you+expect%3F+&amp;url=http://test.ical.ly/2010/07/22/unit-testing-symfony-plugins-with-phpunit-my-session-at-the-symfony-day-2010-what-do-you-expect/&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Submit this to Netvibes&quot;&gt;Submit this to Netvibes&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-reddit&quot;&gt;
			&lt;a href=&quot;http://reddit.com/submit?url=http://test.ical.ly/2010/07/22/unit-testing-symfony-plugins-with-phpunit-my-session-at-the-symfony-day-2010-what-do-you-expect/&amp;title=Unit+testing+symfony+plugins+with+PHPUnit+-+My+session+at+the+symfony+day+2010.+What+do+you+expect%3F+&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on Reddit&quot;&gt;Share this on Reddit&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-stumbleupon&quot;&gt;
			&lt;a href=&quot;http://www.stumbleupon.com/submit?url=http://test.ical.ly/2010/07/22/unit-testing-symfony-plugins-with-phpunit-my-session-at-the-symfony-day-2010-what-do-you-expect/&amp;title=Unit+testing+symfony+plugins+with+PHPUnit+-+My+session+at+the+symfony+day+2010.+What+do+you+expect%3F+&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Stumble upon something good? Share it on StumbleUpon&quot;&gt;Stumble upon something good? Share it on StumbleUpon&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-twitter&quot;&gt;
			&lt;a href=&quot;http://twitter.com/home?status=Unit+testing+symfony+plugins+with+PHPUnit+-+My+session+at+the+symfony+day+2010.+%5B..%5D+-+http://bit.ly/andoZn&amp;source=shareaholic&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Tweet This!&quot;&gt;Tweet This!&lt;/a&gt;
		&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;/div&gt;
&lt;/div&gt;</content>
		<author>
			<name>Christian</name>
			<uri>http://test.ical.ly</uri>
		</author>
		<source>
			<title type="html">test.ical.ly &#187; phpUnit</title>
			<subtitle type="html">getting PHP by the balls</subtitle>
			<link rel="self" href="http://test.ical.ly/tags/phpunit/feed/atom/"/>
			<id>http://test.ical.ly/feed/atom/</id>
			<updated>2010-09-01T00:00:27+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Wrapping symfonys functional tests in a PHPUnit test case</title>
		<link href="http://test.ical.ly/2010/07/07/wrapping-symfonys-functional-tests-in-a-phpunit-test-case/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=wrapping-symfonys-functional-tests-in-a-phpunit-test-case"/>
		<id>http://test.ical.ly/?p=1113</id>
		<updated>2010-07-06T11:50:43+00:00</updated>
		<content type="html">&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/07/wrapping.png&quot;&gt;&lt;img class=&quot;alignleft size-medium wp-image-1114&quot; title=&quot;wrapping&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/07/wrapping-215x300.png&quot; alt=&quot;&quot; width=&quot;215&quot; height=&quot;300&quot; /&gt;&lt;/a&gt;Yesterday I wrote a lot of functional tests for a symfony plugin that provides and XML web service interface.&lt;/p&gt;
&lt;p&gt;Using symfonys functional testing classes this is actually quite easy to do.&lt;/p&gt;
&lt;p&gt;But wouldn&amp;#8217;t it be cool if you could integrate these tests into your continuous integration service just like PHPUnit tests? Wouldn&amp;#8217;t it be cool to be able to generate PHPUnit coverage reports?&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1113&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Well I thought so too that&amp;#8217;s why I decided to write a very simple PHPUnit test case that executes the functional tests (using lime) and runs asserts on the output of those.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;php&quot;&gt;&lt;span&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;/** central bootstrap for unit tests */&lt;/span&gt;
&lt;span&gt;require_once&lt;/span&gt; &lt;span&gt;dirname&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;__FILE__&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;'/bootstrap/functional.php'&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;/** PHPUnit Framework */&lt;/span&gt;
&lt;span&gt;require_once&lt;/span&gt; &lt;span&gt;'PHPUnit/Framework.php'&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;class&lt;/span&gt; yourPluginFunctionalTest &lt;span&gt;extends&lt;/span&gt; PHPUnit_Framework_Testcase
&lt;span&gt;&amp;#123;&lt;/span&gt;
  &lt;span&gt;public&lt;/span&gt; &lt;span&gt;function&lt;/span&gt; testIndex&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
  &lt;span&gt;&amp;#123;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertLimeReport&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'Index'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
  &lt;span&gt;public&lt;/span&gt; &lt;span&gt;function&lt;/span&gt; testShow&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
  &lt;span&gt;&amp;#123;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertLimeReport&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'Show'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
  &lt;span&gt;private&lt;/span&gt; &lt;span&gt;function&lt;/span&gt; assertLimeReport&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$action&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
  &lt;span&gt;&amp;#123;&lt;/span&gt;
    &lt;span&gt;ob_start&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;include&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;dirname&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;__FILE__&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;'/functional/yourModuleActions'&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;$action&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;'Test.php'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$output&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;ob_get_clean&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$lines&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;explode&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;span&gt;\n&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;$output&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;foreach&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$lines&lt;/span&gt; &lt;span&gt;as&lt;/span&gt; &lt;span&gt;$line&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
    &lt;span&gt;&amp;#123;&lt;/span&gt;
      &lt;span&gt;if&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;trim&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$line&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt; &lt;span&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span&gt;'#'&lt;/span&gt; &lt;span&gt;!=&lt;/span&gt; &lt;span&gt;$line&lt;/span&gt;&lt;span&gt;&amp;#91;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&amp;#93;&lt;/span&gt; &lt;span&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span&gt;'&amp;gt;'&lt;/span&gt; &lt;span&gt;!=&lt;/span&gt; &lt;span&gt;$line&lt;/span&gt;&lt;span&gt;&amp;#91;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&amp;#93;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
      &lt;span&gt;&amp;#123;&lt;/span&gt;
        &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertEquals&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'ok'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;substr&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$line&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;2&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;$line&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
      &lt;span&gt;&amp;#125;&lt;/span&gt;
    &lt;span&gt;&amp;#125;&lt;/span&gt;
  &lt;span&gt;&amp;#125;&lt;/span&gt;
&lt;span&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You can see that I used a simple convention how to name the functional tests. There is actually one file per action with the action name encoded in the file name. In the above example I run the tests for executeIndex() and executeShow().&lt;/p&gt;
&lt;p&gt;The rest is simple as well (and can for sure be done far more elegant). I just iterate over the lime output and check for result lines that start with &lt;em&gt;ok&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I also wrote a small &lt;em&gt;phpunit.functional.xml&lt;/em&gt; configuration file so the coverage reports only considers my module code (all other code is unit tested of course).&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;xml&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;lt;?xml&lt;/span&gt; &lt;span&gt;version&lt;/span&gt;=&lt;span&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt; &lt;span&gt;encoding&lt;/span&gt;=&lt;span&gt;&amp;quot;UTF-8&amp;quot;&lt;/span&gt;&lt;span&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;&lt;span&gt;&amp;lt;phpunit&lt;/span&gt; &lt;span&gt;backupGlobals&lt;/span&gt;=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;         &lt;span&gt;backupStaticAttributes&lt;/span&gt;=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;         &lt;span&gt;colors&lt;/span&gt;=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;         &lt;span&gt;convertErrorsToExceptions&lt;/span&gt;=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;         &lt;span&gt;convertNoticesToExceptions&lt;/span&gt;=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;         &lt;span&gt;convertWarningsToExceptions&lt;/span&gt;=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;         &lt;span&gt;processIsolation&lt;/span&gt;=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;         &lt;span&gt;stopOnFailure&lt;/span&gt;=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;         &lt;span&gt;syntaxCheck&lt;/span&gt;=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&amp;nbsp;
  &lt;span&gt;&lt;span&gt;&amp;lt;filter&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;whitelist&lt;/span&gt; &lt;span&gt;addUncoveredFilesFromWhitelist&lt;/span&gt;=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;directory&lt;/span&gt; &lt;span&gt;suffix&lt;/span&gt;=&lt;span&gt;&amp;quot;.class.php&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;./modules/yourModule/actions/&lt;span&gt;&lt;span&gt;&amp;lt;/directory&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;directory&lt;/span&gt; &lt;span&gt;suffix&lt;/span&gt;=&lt;span&gt;&amp;quot;.class.php&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;./modules/yourModule/lib/&lt;span&gt;&lt;span&gt;&amp;lt;/directory&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;/whitelist&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;/filter&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/phpunit&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Running this test case is easy.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;sh&quot;&gt;$ phpunit --configuration=phpunit.functional.xml --coverage-html=/path/to/your/report test/yourPluginFunctionalTests.php&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The coverage report comes in quite handy as I can now see which methods are not executed and are probably not needed any longer (I did some heavy refactoring on this).&lt;/p&gt;
&lt;p&gt;The only thin I can not get rid of is that lime will only have the last word telling me &amp;#8220;&lt;em&gt;# Looks like everything went fine.&lt;/em&gt;&amp;#8220;.&lt;/p&gt;
&lt;p&gt;This is due to limes use of &lt;code&gt;register_shutdown_function()&lt;/code&gt; which unfortunately does not have a counter part to unregister..&lt;/p&gt;


&lt;div class=&quot;shr-bookmarks shr-bookmarks-expand shr-bookmarks-bg-shr&quot;&gt;
&lt;ul class=&quot;socials&quot;&gt;
		&lt;li class=&quot;shr-delicious&quot;&gt;
			&lt;a href=&quot;http://delicious.com/post?url=http://test.ical.ly/2010/07/07/wrapping-symfonys-functional-tests-in-a-phpunit-test-case/&amp;title=Wrapping+symfonys+functional+tests+in+a+PHPUnit+test+case&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on del.icio.us&quot;&gt;Share this on del.icio.us&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-linkedin&quot;&gt;
			&lt;a href=&quot;http://www.linkedin.com/shareArticle?mini=true&amp;url=http://test.ical.ly/2010/07/07/wrapping-symfonys-functional-tests-in-a-phpunit-test-case/&amp;title=Wrapping+symfonys+functional+tests+in+a+PHPUnit+test+case&amp;summary=Yesterday%20I%20wrote%20a%20lot%20of%20functional%20tests%20for%20a%20symfony%20plugin%20that%20provides%20and%20XML%20web%20service%20interface.%0D%0A%0D%0AUsing%20symfonys%20functional%20testing%20classes%20this%20is%20actually%20quite%20easy%20to%20do.%0D%0A%0D%0ABut%20wouldn%27t%20it%20be%20cool%20if%20you%20could%20integrate%20these%20tests%20into%20your%20continuous%20integration%20service%20just%20li&amp;source=test.ical.ly&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on LinkedIn&quot;&gt;Share this on LinkedIn&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-mail&quot;&gt;
			&lt;a href=&quot;mailto:?subject=%22Wrapping%20symfonys%20functional%20tests%20in%20a%20PHPUnit%20test%20case%22&amp;body=Link: http://test.ical.ly/2010/07/07/wrapping-symfonys-functional-tests-in-a-phpunit-test-case/ (sent via shareaholic)%0D%0A%0D%0A----%0D%0A Yesterday%20I%20wrote%20a%20lot%20of%20functional%20tests%20for%20a%20symfony%20plugin%20that%20provides%20and%20XML%20web%20service%20interface.%0D%0A%0D%0AUsing%20symfonys%20functional%20testing%20classes%20this%20is%20actually%20quite%20easy%20to%20do.%0D%0A%0D%0ABut%20wouldn%27t%20it%20be%20cool%20if%20you%20could%20integrate%20these%20tests%20into%20your%20continuous%20integration%20service%20just%20li&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Email this to a friend?&quot;&gt;Email this to a friend?&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-misterwong&quot;&gt;
			&lt;a href=&quot;http://www.mister-wong.com/addurl/?bm_url=http://test.ical.ly/2010/07/07/wrapping-symfonys-functional-tests-in-a-phpunit-test-case/&amp;bm_description=Wrapping+symfonys+functional+tests+in+a+PHPUnit+test+case&amp;plugin=sexybookmarks&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Add this to Mister Wong&quot;&gt;Add this to Mister Wong&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-netvibes&quot;&gt;
			&lt;a href=&quot;http://www.netvibes.com/share?title=Wrapping+symfonys+functional+tests+in+a+PHPUnit+test+case&amp;url=http://test.ical.ly/2010/07/07/wrapping-symfonys-functional-tests-in-a-phpunit-test-case/&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Submit this to Netvibes&quot;&gt;Submit this to Netvibes&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-reddit&quot;&gt;
			&lt;a href=&quot;http://reddit.com/submit?url=http://test.ical.ly/2010/07/07/wrapping-symfonys-functional-tests-in-a-phpunit-test-case/&amp;title=Wrapping+symfonys+functional+tests+in+a+PHPUnit+test+case&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on Reddit&quot;&gt;Share this on Reddit&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-stumbleupon&quot;&gt;
			&lt;a href=&quot;http://www.stumbleupon.com/submit?url=http://test.ical.ly/2010/07/07/wrapping-symfonys-functional-tests-in-a-phpunit-test-case/&amp;title=Wrapping+symfonys+functional+tests+in+a+PHPUnit+test+case&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Stumble upon something good? Share it on StumbleUpon&quot;&gt;Stumble upon something good? Share it on StumbleUpon&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-twitter&quot;&gt;
			&lt;a href=&quot;http://twitter.com/home?status=Wrapping+symfonys+functional+tests+in+a+PHPUnit+test+case+-+http://bit.ly/aUuBs4&amp;source=shareaholic&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Tweet This!&quot;&gt;Tweet This!&lt;/a&gt;
		&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;/div&gt;
&lt;/div&gt;</content>
		<author>
			<name>Christian</name>
			<uri>http://test.ical.ly</uri>
		</author>
		<source>
			<title type="html">test.ical.ly &#187; phpUnit</title>
			<subtitle type="html">getting PHP by the balls</subtitle>
			<link rel="self" href="http://test.ical.ly/tags/phpunit/feed/atom/"/>
			<id>http://test.ical.ly/feed/atom/</id>
			<updated>2010-09-01T00:00:27+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">State of Symfony 2 online conference &amp;#8211; a killer feature revealed!</title>
		<link href="http://test.ical.ly/2010/06/23/state-of-symfony-2-online-conference-a-killer-feature-revealed/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=state-of-symfony-2-online-conference-a-killer-feature-revealed"/>
		<id>http://test.ical.ly/?p=1052</id>
		<updated>2010-06-22T18:10:41+00:00</updated>
		<content type="html">&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/06/the-state-of-symfony-live-2010.png&quot;&gt;&lt;img class=&quot;alignleft size-full wp-image-1054&quot; title=&quot;the-state-of-symfony-live-2010&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/06/the-state-of-symfony-live-2010.png&quot; alt=&quot;&quot; width=&quot;215&quot; height=&quot;120&quot; /&gt;&lt;/a&gt;Yesterday I attended the &lt;a title=&quot;&quot;&gt;The State of Symfony 2 online conference&lt;/a&gt;. Actually my first online conference so it was quite exciting.&lt;/p&gt;
&lt;p&gt;One of the most exciting questions though was:&#160;&lt;em&gt;What is this new killer feature?&lt;/em&gt; Well,&#160;&lt;a title=&quot;The State of Symfony 2 &#8211; Online conference to reveal the next killer feature&quot; href=&quot;http://test.ical.ly/2010/06/21/the-state-of-symfony-2-online-conference-to-reveal-the-next-killer-feature/&quot; target=&quot;_blank&quot;&gt;I made my guess before&lt;/a&gt; but lets see if I was right.&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1052&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;A few minutes before the first session there were already more than 100 people connected to the collaboration platform (&lt;a href=&quot;http://www.elluminate.com/&quot;&gt;http://www.elluminate.com/&lt;/a&gt;). Not a bad turnout for &amp;#8220;just an online conference&amp;#8221;.&lt;/p&gt;
&lt;p&gt;The tool features moderation, listening as well as speaking, voting, a whiteboard, file transfers, a group chat and probably a lot more. It seemed a suitable choice.&lt;/p&gt;
&lt;p&gt;Please excuse this article to be somewhat bullet-point-ish but I wrote most of it while listening to the sessions and I guess you will get the meaning anyway. &lt;img src=&quot;http://test.ical.ly/wp-includes/images/smilies/icon_smile.gif&quot; alt=&quot;:)&quot; class=&quot;wp-smiley&quot; /&gt; &lt;/p&gt;
&lt;h2&gt;Miscellaneous enhancements&#160;&lt;em&gt;&lt;span&gt;Fabien Potencier&lt;/span&gt;&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;The philosophy of Symfony 2 is to be as flexible as possible but with sensible defaults so it can be used right out of the box but possible to be changed to everything you need.&#160;Symfony 2 now also adapts PEAR standards to allow easy integration of non-symfony libraries rather than setting its own standards.&lt;/p&gt;
&lt;p&gt;As much as possible went was put into the components to make sure they don&amp;#8217;t depend on the MVC framework and can run standalone. This as well eases the use by Symfony newbies as well as experts.&lt;/p&gt;
&lt;p&gt;Fabien introduced the latest additions to the components library.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CssSelector&lt;/strong&gt; developed from scratch converts CSS selector to their XPath equivalents.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DomCrawler&lt;/strong&gt; was based on symfony 1 browser class and can navigate the DOM. Its methods are chainable, it can utilise CssSelector but uses XPath internally and its API feels jQuery like.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Browser&lt;/strong&gt; is an HTTP client implemented in PHP that can even manage cookies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Finder&lt;/strong&gt; is completely rewritten from its symfony 1 version and now implements PHPs Iterator interface. It&amp;#8217;s chainable and provides easy to use date filters. The method signatures are standardised and instead of file handles it returns SplFileInfo instances. It can also work with streams like on the Zend FWs Amazon S3 Stream.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HttpKernel&lt;/strong&gt; is a framework construction kit and replaces the former RequestHandler. It has a very simple interface with only two methods getRequest() and handle(). It also includes a Profiler and the WebDebugToolbar functionalities.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All components are decoupled and therefore fully testable.&lt;/p&gt;
&lt;p&gt;With these and the already known components Symfony 2 is not yet ready but &lt;strong&gt;&lt;em&gt;the&#160;main concepts and overall philosophy will not change anymore&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;From the Q&amp;amp;A at the end of the session we learned that at this point there will be no migration tool from symfony 1 to Symfony 2 but there will &lt;em&gt;probably&lt;/em&gt; be an intermediate layer once Symfony 2 is ready.&lt;/p&gt;
&lt;p&gt;However the API can change at any time! So &lt;em&gt;&lt;strong&gt;for production use sf1.4 is still recommended&lt;/strong&gt;&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;The first alpha version planned for September.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Symfony 2 Meets Propel 1.5 &lt;span&gt;&lt;em&gt;&lt;span&gt;Fran&#231;ois Zaninotto&lt;/span&gt;&lt;/em&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;I don&amp;#8217;t really use Propel but still I was interested in its latest developments.&lt;/p&gt;
&lt;p&gt;Propel 1.5 is fully backwards compatible with Propel 1.3 and 1.4. It&amp;#8217;s faster, very IDE friendly, better documented, has three times more unit tests as Propel 1.3 and is fully integrated into symfony 1.4 using the sfPropel15Plugin.&lt;/p&gt;
&lt;p&gt;Announced as one of the killer features come the model queries which are supposed to be to SQL what ActiveRecord is to the table row. To me it looked like a clone of Doctrines DQL but with domain specific method names..&lt;/p&gt;
&lt;p&gt;Next killer feature and missing in Doctrine 1.2 is concrete table inheritance! But on the database level it is actually denormalised meaning that columns defined on the parent model are stored in the child tables as well for performance reasons. I wouldn&amp;#8217;t really consider this to be concrete but composite and I remember having done something similar in Doctrine as well..&lt;/p&gt;
&lt;p&gt;The third killer feature still to come will be the&#160;aggregate_column behaviour which utilises aggregation functions and stores and maintains their results in extra table columns.&lt;/p&gt;
&lt;p&gt;Well, Propel is not dead but I am not convinced of its killer instinct and frankly I am annoyed by all this Doctrine bashing. If Propel is a good ORM (what it is to many users) then I should be able co-exist with other solutions! I think the major difference between Propel 1.5 and Doctrine 2 is that Propel is still an ActiveRecord which some might prefer. Not me though.&lt;/p&gt;
&lt;p&gt;Funnily after the presentation a poll was setup whether to prefer Propel or Doctrine and when I had a look it was 76% favouring Doctrine. &lt;img src=&quot;http://test.ical.ly/wp-includes/images/smilies/icon_wink.gif&quot; alt=&quot;;)&quot; class=&quot;wp-smiley&quot; /&gt;  &lt;a href=&quot;http://twtpoll.com/r/545mw5&quot;&gt;http://twtpoll.com/r/545mw5&lt;/a&gt;. Nowhere near representative but entertaining.&lt;/p&gt;
&lt;h2&gt;What&amp;#8217;s new in the Doctrine 2 Symfony Integration &lt;em&gt;&lt;span&gt;Jonathan Wage&lt;/span&gt;&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;Jonathans session didn&amp;#8217;t bring too many news for you when you followed his talks and tweets regularly but it was a good and up to date wrap up of the current implementation.&lt;/p&gt;
&lt;p&gt;Next to the DoctrineBundle for Symfony 2 there now is also a&#160;MondoDB Object Document Mapper bundle (ODM not ORM!) and a bundle for the beloved&#160;Doctrine Migrations with unchanged functionality.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s Doctrines Architecture in a nutshell.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;DBAL&lt;/strong&gt; is responsible for managing connections and creating/dropping databases and running dql from the command line.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;ORM&lt;/strong&gt; has the &lt;strong&gt;EntitiyManager&lt;/strong&gt; which persists and retrieves entities. You can have multiple instances (i.e. per database connection) of it.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;Entity&lt;/strong&gt; is a regular PHP object, no more magic, clean and testable, fast and only limited by PHP and now you can use the constructor as you like to.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One nice little thing I like is the new command line task that ensures your production settings! But also tasks for cache control are a nice addition.&lt;/p&gt;
&lt;p&gt;DQL now uses a proper lexer/parser and has a strict BNF which allows for helpful syntax errors rather than side effects!&lt;/p&gt;
&lt;p&gt;During development you can now change your schema without throwing away your database. Instead a schema update compares your current database layout and your current schema changes to update only what is necessary.&lt;/p&gt;
&lt;p&gt;The MongoDB ODM shares the same architecture as ORM only with a DocumentManager instead of an EntitiyManager. Its&#160;DocumentManager makes full use of the MongoDB API.&lt;/p&gt;
&lt;p&gt;You can even remap objects from Document to Entity and back during development and even during runtime. So fetching a model from the database and saving it to MongoDB should be possible.&lt;/p&gt;
&lt;p&gt;Currently only MongoDB is supported and there is no support for CouchDB yet.&lt;/p&gt;
&lt;p&gt;Finally Doctrines ORM supports class table inheritance but after seen the Propel version of it I have to take deeper look before I&amp;#8217;m amazed. &lt;img src=&quot;http://test.ical.ly/wp-includes/images/smilies/icon_wink.gif&quot; alt=&quot;;)&quot; class=&quot;wp-smiley&quot; /&gt; &lt;/p&gt;
&lt;h2&gt;Unit &amp;amp; Functional Tests&#160;&lt;span&gt;&lt;em&gt;&lt;span&gt;Fabien Potencier&lt;/span&gt;&lt;/em&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;Symfony 2 switched from lime to PHPUnit 3.5 because of standardisation (top prio as the framework is easier to learn that way).&#160;lime at the time was an easy option to PHP testing when unit testing had not yet arrived in the PHP world. By using PHPUnit Symfony can now benefit from yet another community while focussing on the framework and some improvements went back to PHPUnit already.&lt;/p&gt;
&lt;p&gt;While this is great in itself it gets better when Fabien shares two best practices.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There should be no more AllTests.php. Instead you can use phpunit.xml (it has a bootstrap attribute!).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/06/phpunit.xml_.jpg&quot;&gt;&lt;img class=&quot;size-medium wp-image-1056 alignnone&quot; title=&quot;phpunit.xml&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/06/phpunit.xml_-300x219.jpg&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;219&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt; &lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Don&amp;#8217;t unit test your controllers! Controllers are not unit tested because they should only contain glue code and no business logic.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The functional test framework now has a cleaner API and utilises DomCrawler and Browser components.&lt;/p&gt;
&lt;p&gt;Functional tests now only test the response object, which is exactly what you receive then the request is handled by your controller.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/06/functional-tests.jpg&quot;&gt;&lt;img class=&quot;size-medium wp-image-1057 alignnone&quot; title=&quot;functional-tests&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/06/functional-tests-300x225.jpg&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;225&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can have multiple instances of the Browser so that you can even test the interaction of multiple clients. Even when you use a library with static states this will work as for each Browser a new PHP process will be created.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/06/functional-tests-forking.jpg&quot;&gt;&lt;img class=&quot;size-medium wp-image-1058 alignnone&quot; title=&quot;functional-tests-forking&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/06/functional-tests-forking-300x195.jpg&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;195&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Because the functional tests are using the Browser component they can even be run on your production environment for monitoring purposes utilising the profiler of the request. Even testing of non-symfony websites is possible!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/06/profiler.png&quot;&gt;&lt;img class=&quot;alignnone size-medium wp-image-1059&quot; title=&quot;profiler&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/06/profiler-300x185.png&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;185&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;The new form framework &lt;span&gt;&lt;em&gt;&lt;span&gt;Bernhard Schussek&lt;/span&gt;&lt;/em&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;After all the experience with the form framework of symfony 1 the new incarnation now got a whole new architecture and was completely redesigned for simplicity and reusability.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;#8220;Symfony 2 embraces your domain model&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Validators now validate domain models and forms.&lt;/p&gt;
&lt;p&gt;Form fields are fully culture aware (localised)&#160;and can be grouped to &amp;#8220;lightweight subforms&amp;#8221; that become a widget like i.e. a google maps locator widget.&lt;/p&gt;
&lt;p&gt;CollectionFields can be used to add lists of fields for 1-n relations.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/06/form-fields.jpg&quot;&gt;&lt;img class=&quot;alignnone size-medium wp-image-1060&quot; title=&quot;form-fields&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/06/form-fields-300x182.jpg&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;182&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The form framework is of course also a standalone library that does not depend on without Symfony 2.&lt;/p&gt;
&lt;p&gt;Constraints can be added using annotations or XML or Yaml even using callbacks on your models so you can easily implement dynamic constraints.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/06/constraints.jpg&quot;&gt;&lt;img class=&quot;alignnone size-medium wp-image-1061&quot; title=&quot;constraints&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/06/constraints-300x184.jpg&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;184&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If forms are now directly modelled on your domain objects then how can you do embedded forms? Well you can&amp;#8217;t or at least not as you do in symfony 1. For example if you want to have a form for a user registration based on the user model but with additional fields for terms and conditions or newsletter subscriptions then you have to create a new model Registration first. This may seem like additional effort but if you think about it it makes a lot more sense.&lt;/p&gt;
&lt;p&gt;Constraints can also be sequenced i.e. to save on resources when validating cheap constraints first before validating more costly ones that may contain a web service call.&lt;/p&gt;
&lt;p&gt;HTML 5 input fields are not yet supported but the forms and validators and fields and everything is&#160;fully internationalisationable.&lt;/p&gt;
&lt;p&gt;This sounds like something to really look forward to as the forms of symfony 1.2+ were certainly better than previous versions but had a lot of design flaws which make them feel unintuitive.&lt;/p&gt;
&lt;h2&gt;The Symfony 2 Killer Feature&amp;#8230; &lt;span&gt;&lt;em&gt;&lt;span&gt;Fabien Potencier&lt;/span&gt;&lt;/em&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;I was right! &lt;img src=&quot;http://test.ical.ly/wp-includes/images/smilies/icon_smile.gif&quot; alt=&quot;:)&quot; class=&quot;wp-smiley&quot; /&gt; &lt;/p&gt;
&lt;p&gt;&amp;#8220;Caching on the Edge&amp;#8221;&lt;/p&gt;
&lt;p&gt;According to yet another benchmark test Symfony 2 will be much faster than symfony 1 and even faster with more concurrent requests. All this is caused by the new killer feature: the cache.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/06/php-http-accelerator.jpg&quot;&gt;&lt;img class=&quot;alignnone size-medium wp-image-1062&quot; title=&quot;php-http-accelerator&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/06/php-http-accelerator-300x46.jpg&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;46&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Just like Varnish, Squid or Akamai Symfony 2 provides an HTTP cache or reverse proxy implemented in PHP. Symfony 2 also implements the related HTTP&#160;specifications and uses the cache headers for controlling the cache behaviour. This means that you can easily replace the PHP cache with Varnish or Akamai without the need to change.&lt;/p&gt;
&lt;p&gt;And the cache classes are very easily integrated as they decorate the kernel. They can&#160;therefore be activated even for functional tests.&lt;/p&gt;
&lt;p&gt;What about when parts of the page must be cached less?&lt;/p&gt;
&lt;p&gt;Yes the best bit is still to come. Symfony 2 also implements the&#160;Edge Side Include (ESI) specifications written by Akamai which can be used to cache parts of the pages differently from the rest. This is accomplished by the view part of the MVC pattern which can return every partial separately if I understood correctly. You can even use other webpages as partials. Well, I have to digg into this at some point but I am utterly amazed of the completeness of the design.&lt;/p&gt;
&lt;p&gt;I can see that it forces you to better separation of concerns as you have to think about your cache times early in the process. Which is good.&lt;/p&gt;
&lt;p&gt;To sum it all up: the cache layer is separated from the framework. This does not only mean that you can exchange it with other reverse proxies it only means that for each page request that can be answered by the cache layer the kernel of the framework is not even booted! Symfony 2 also implements&#160;stale-while-revalidate and&#160;stale-if-error. Go and google it if you don&amp;#8217;t know what this is, it is absolutely fantastic!&lt;/p&gt;
&lt;p&gt;Another best practice advise:&lt;/p&gt;
&lt;p&gt;If you have to think about invalidating the cache then you are most likely using expiration instead of validation. In other words: for dynamic parts you should let the cache validate the cache instead of setting an expire time. Cache validation is soon going to be automatically optimised. I&amp;#8217;m curious how this will work.&lt;/p&gt;
&lt;p&gt;However great this all sounds for now you have to remember that everything is still experimental.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Well what can I say except that Symfony 2 feels so right on so many levels. This might even have a big impact on the whole PHP community. Can&amp;#8217;t wait until it&amp;#8217;s stable in 2011!&lt;/p&gt;


&lt;div class=&quot;shr-bookmarks shr-bookmarks-expand shr-bookmarks-bg-shr&quot;&gt;
&lt;ul class=&quot;socials&quot;&gt;
		&lt;li class=&quot;shr-delicious&quot;&gt;
			&lt;a href=&quot;http://delicious.com/post?url=http://test.ical.ly/2010/06/23/state-of-symfony-2-online-conference-a-killer-feature-revealed/&amp;title=State+of+Symfony+2+online+conference+-+a+killer+feature+revealed%21&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on del.icio.us&quot;&gt;Share this on del.icio.us&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-linkedin&quot;&gt;
			&lt;a href=&quot;http://www.linkedin.com/shareArticle?mini=true&amp;url=http://test.ical.ly/2010/06/23/state-of-symfony-2-online-conference-a-killer-feature-revealed/&amp;title=State+of+Symfony+2+online+conference+-+a+killer+feature+revealed%21&amp;summary=Yesterday%20I%20attended%20the%20The%20State%20of%20Symfony%202%20online%20conference.%20Actually%20my%20first%20online%20conference%20so%20it%20was%20quite%20exciting.%20One%20of%20the%20most%20exciting%20questions%20though%20was%3A%C2%A0What%20is%20this%20new%20killer%20feature%3F%20Well%2C%C2%A0I%20made%20my%20guess%20before%20but%20lets%20see%20if%20I%20was%20right.%20%20A%20few%20minutes%20before%20the%20first&amp;source=test.ical.ly&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on LinkedIn&quot;&gt;Share this on LinkedIn&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-mail&quot;&gt;
			&lt;a href=&quot;mailto:?subject=%22State%20of%20Symfony%202%20online%20conference%20-%20a%20killer%20feature%20revealed%21%22&amp;body=Link: http://test.ical.ly/2010/06/23/state-of-symfony-2-online-conference-a-killer-feature-revealed/ (sent via shareaholic)%0D%0A%0D%0A----%0D%0A Yesterday%20I%20attended%20the%20The%20State%20of%20Symfony%202%20online%20conference.%20Actually%20my%20first%20online%20conference%20so%20it%20was%20quite%20exciting.%20One%20of%20the%20most%20exciting%20questions%20though%20was%3A%C2%A0What%20is%20this%20new%20killer%20feature%3F%20Well%2C%C2%A0I%20made%20my%20guess%20before%20but%20lets%20see%20if%20I%20was%20right.%20%20A%20few%20minutes%20before%20the%20first&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Email this to a friend?&quot;&gt;Email this to a friend?&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-misterwong&quot;&gt;
			&lt;a href=&quot;http://www.mister-wong.com/addurl/?bm_url=http://test.ical.ly/2010/06/23/state-of-symfony-2-online-conference-a-killer-feature-revealed/&amp;bm_description=State+of+Symfony+2+online+conference+-+a+killer+feature+revealed%21&amp;plugin=sexybookmarks&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Add this to Mister Wong&quot;&gt;Add this to Mister Wong&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-netvibes&quot;&gt;
			&lt;a href=&quot;http://www.netvibes.com/share?title=State+of+Symfony+2+online+conference+-+a+killer+feature+revealed%21&amp;url=http://test.ical.ly/2010/06/23/state-of-symfony-2-online-conference-a-killer-feature-revealed/&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Submit this to Netvibes&quot;&gt;Submit this to Netvibes&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-reddit&quot;&gt;
			&lt;a href=&quot;http://reddit.com/submit?url=http://test.ical.ly/2010/06/23/state-of-symfony-2-online-conference-a-killer-feature-revealed/&amp;title=State+of+Symfony+2+online+conference+-+a+killer+feature+revealed%21&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on Reddit&quot;&gt;Share this on Reddit&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-stumbleupon&quot;&gt;
			&lt;a href=&quot;http://www.stumbleupon.com/submit?url=http://test.ical.ly/2010/06/23/state-of-symfony-2-online-conference-a-killer-feature-revealed/&amp;title=State+of+Symfony+2+online+conference+-+a+killer+feature+revealed%21&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Stumble upon something good? Share it on StumbleUpon&quot;&gt;Stumble upon something good? Share it on StumbleUpon&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-twitter&quot;&gt;
			&lt;a href=&quot;http://twitter.com/home?status=State+of+Symfony+2+online+conference+-+a+killer+feature+revealed%21+-+http://bit.ly/cU5KOi&amp;source=shareaholic&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Tweet This!&quot;&gt;Tweet This!&lt;/a&gt;
		&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;/div&gt;
&lt;/div&gt;</content>
		<author>
			<name>Christian</name>
			<uri>http://test.ical.ly</uri>
		</author>
		<source>
			<title type="html">test.ical.ly &#187; phpUnit</title>
			<subtitle type="html">getting PHP by the balls</subtitle>
			<link rel="self" href="http://test.ical.ly/tags/phpunit/feed/atom/"/>
			<id>http://test.ical.ly/feed/atom/</id>
			<updated>2010-09-01T00:00:27+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">phpUnderControl 0.6.0beta2 released</title>
		<link href="http://www.manuel-pichler.de/archives/92-phpUnderControl-0.6.0beta2-released.html"/>
		<id>http://www.manuel-pichler.de/archives/92-guid.html</id>
		<updated>2010-06-10T10:25:00+00:00</updated>
		<content type="html">&lt;p&gt;
  Today I have released the &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2382&amp;entry_id=92&quot; title=&quot;http://github.com/manuelpichler/phpUnderControl/tree/0.6.0beta2&quot;&gt;second beta&lt;/a&gt; version of &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2383&amp;entry_id=92&quot; title=&quot;http://php-under-control.org&quot;&gt;phpUnderControl&lt;/a&gt;. Beside several minor tweaks and bug fixes, this release contains one additional feature I was asked for during the &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2384&amp;entry_id=92&quot; title=&quot;http://it-republik.de/php/phpconference/&quot;&gt;IPC&lt;/a&gt; in Berlin. This feature allows you to specify a maximum number of log entries that will be shown in the generated metric charts. This can be very useful once you have a project with a great amount of builds and the chart rendering gets slower and slower.
&lt;/p&gt;

&lt;p&gt;
  This feature adds a new option &lt;code&gt;--max-number&lt;/code&gt; to phpUnderControl's &lt;code&gt;chart&lt;/code&gt; command. To rebuild all your charts you can call phpUnderControl's shell script with the following command:
&lt;/p&gt;

&lt;pre&gt;
  mapi@arwen ~ $ phpuc --force-update --max-number 42 \
                 /opt/cruisecontrol/logs/phpUnderControl \
                 /opt/cruisecontrol/logs/phpUnderControl
&lt;/pre&gt;

&lt;p&gt;
  You can get the latest release of phpUnderControl through its pear channel:
&lt;/p&gt;

&lt;pre&gt;
  mapi@arwen ~ $ pear upgrade --alldeps phpuc/phpUnderControl-0.6.0beta2
  Starting to download phpUnderControl-0.6.0beta2.tgz (546,314 bytes)
  ...................................................................
  .............................done: 546,314 bytes
&lt;/pre&gt;

&lt;p&gt;
  or you can get the latest development version on &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2386&amp;entry_id=92&quot; title=&quot;http://github.com/manuelpichler/phpUnderControl&quot;&gt;github&lt;/a&gt;.
&lt;/p&gt;</content>
		<author>
			<name>Manuel Pichler</name>
			<email>nospam@example.com</email>
			<uri>http://www.manuel-pichler.de/</uri>
		</author>
		<source>
			<title type="html">Manuel Pichler - phpundercontrol</title>
			<subtitle type="html">Trust is good, (phpUnder)Control is better.</subtitle>
			<link rel="self" href="http://manuel-pichler.de/feeds/categories/10-phpundercontrol.rss"/>
			<id>http://manuel-pichler.de/feeds/categories/10-phpundercontrol.rss</id>
			<updated>2010-06-10T11:00:28+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">StreamHitching &amp;#8211; stream wrapper mini framework alpha version now fully PHPUnit tested</title>
		<link href="http://test.ical.ly/2010/06/09/streamhitching-stream-wrapper-mini-framework-alpha-version-now-fully-phpunit-tested/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=streamhitching-stream-wrapper-mini-framework-alpha-version-now-fully-phpunit-tested"/>
		<id>http://test.ical.ly/?p=979</id>
		<updated>2010-06-08T20:40:54+00:00</updated>
		<content type="html">&lt;p&gt;&lt;img class=&quot;alignleft size-medium wp-image-980&quot; title=&quot;present&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/06/present-300x249.jpg&quot; alt=&quot;present&quot; width=&quot;300&quot; height=&quot;249&quot; /&gt;As I &lt;a href=&quot;http://test.ical.ly/2010/06/03/a-hitchhikers-guide-to-php-streams/&quot; target=&quot;_blank&quot;&gt;mentioned before&lt;/a&gt; I am working on a small framework to implement custom stream wrappers.&lt;/p&gt;
&lt;p&gt;For example you can later use this to easily wrap access to a web service or similar.&lt;/p&gt;
&lt;p&gt;As of today I reached a 90+% code coverage and everything passes. Check out the sources and see if some test does not work for you.&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-979&quot;&gt;&lt;/span&gt;I already got the feedback that running Windows there are a few minor issues that I will take care of soon.&lt;/p&gt;
&lt;p&gt;The unit tests themselves might not be the easiest on the eye right now but I am getting there. Also the documentation is not yet written.. remember this is still alpha! &lt;img src=&quot;http://test.ical.ly/wp-includes/images/smilies/icon_wink.gif&quot; alt=&quot;;)&quot; class=&quot;wp-smiley&quot; /&gt; &lt;/p&gt;
&lt;p&gt;So feel free to try and break and contribute by checking out or forking &lt;a title=&quot;StreamHitching&quot; href=&quot;http://github.com/caefer/StreamHitching&quot; target=&quot;_blank&quot;&gt;StreamHitching on GitHub&lt;/a&gt;.&lt;/p&gt;


&lt;div class=&quot;shr-bookmarks shr-bookmarks-expand shr-bookmarks-bg-shr&quot;&gt;
&lt;ul class=&quot;socials&quot;&gt;
		&lt;li class=&quot;shr-delicious&quot;&gt;
			&lt;a href=&quot;http://delicious.com/post?url=http://test.ical.ly/2010/06/09/streamhitching-stream-wrapper-mini-framework-alpha-version-now-fully-phpunit-tested/&amp;title=StreamHitching+-+stream+wrapper+mini+framework+alpha+version+now+fully+PHPUnit+tested&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on del.icio.us&quot;&gt;Share this on del.icio.us&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-linkedin&quot;&gt;
			&lt;a href=&quot;http://www.linkedin.com/shareArticle?mini=true&amp;url=http://test.ical.ly/2010/06/09/streamhitching-stream-wrapper-mini-framework-alpha-version-now-fully-phpunit-tested/&amp;title=StreamHitching+-+stream+wrapper+mini+framework+alpha+version+now+fully+PHPUnit+tested&amp;summary=As%20I%20mentioned%20before%20I%20am%20working%20on%20a%20small%20framework%20to%20implement%20custom%20stream%20wrappers.%0D%0A%0D%0AFor%20example%20you%20can%20later%20use%20this%20to%20easily%20wrap%20access%20to%20a%20web%20service%20or%20similar.%0D%0A%0D%0AAs%20of%20today%20I%20reached%20a%2090%2B%25%20code%20coverage%20and%20everything%20passes.%20Check%20out%20the%20sources%20and%20see%20if%20some%20test%20does%20n&amp;source=test.ical.ly&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on LinkedIn&quot;&gt;Share this on LinkedIn&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-mail&quot;&gt;
			&lt;a href=&quot;mailto:?subject=%22StreamHitching%20-%20stream%20wrapper%20mini%20framework%20alpha%20version%20now%20fully%20PHPUnit%20tested%22&amp;body=Link: http://test.ical.ly/2010/06/09/streamhitching-stream-wrapper-mini-framework-alpha-version-now-fully-phpunit-tested/ (sent via shareaholic)%0D%0A%0D%0A----%0D%0A As%20I%20mentioned%20before%20I%20am%20working%20on%20a%20small%20framework%20to%20implement%20custom%20stream%20wrappers.%0D%0A%0D%0AFor%20example%20you%20can%20later%20use%20this%20to%20easily%20wrap%20access%20to%20a%20web%20service%20or%20similar.%0D%0A%0D%0AAs%20of%20today%20I%20reached%20a%2090%2B%25%20code%20coverage%20and%20everything%20passes.%20Check%20out%20the%20sources%20and%20see%20if%20some%20test%20does%20n&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Email this to a friend?&quot;&gt;Email this to a friend?&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-misterwong&quot;&gt;
			&lt;a href=&quot;http://www.mister-wong.com/addurl/?bm_url=http://test.ical.ly/2010/06/09/streamhitching-stream-wrapper-mini-framework-alpha-version-now-fully-phpunit-tested/&amp;bm_description=StreamHitching+-+stream+wrapper+mini+framework+alpha+version+now+fully+PHPUnit+tested&amp;plugin=sexybookmarks&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Add this to Mister Wong&quot;&gt;Add this to Mister Wong&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-netvibes&quot;&gt;
			&lt;a href=&quot;http://www.netvibes.com/share?title=StreamHitching+-+stream+wrapper+mini+framework+alpha+version+now+fully+PHPUnit+tested&amp;url=http://test.ical.ly/2010/06/09/streamhitching-stream-wrapper-mini-framework-alpha-version-now-fully-phpunit-tested/&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Submit this to Netvibes&quot;&gt;Submit this to Netvibes&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-reddit&quot;&gt;
			&lt;a href=&quot;http://reddit.com/submit?url=http://test.ical.ly/2010/06/09/streamhitching-stream-wrapper-mini-framework-alpha-version-now-fully-phpunit-tested/&amp;title=StreamHitching+-+stream+wrapper+mini+framework+alpha+version+now+fully+PHPUnit+tested&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on Reddit&quot;&gt;Share this on Reddit&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-stumbleupon&quot;&gt;
			&lt;a href=&quot;http://www.stumbleupon.com/submit?url=http://test.ical.ly/2010/06/09/streamhitching-stream-wrapper-mini-framework-alpha-version-now-fully-phpunit-tested/&amp;title=StreamHitching+-+stream+wrapper+mini+framework+alpha+version+now+fully+PHPUnit+tested&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Stumble upon something good? Share it on StumbleUpon&quot;&gt;Stumble upon something good? Share it on StumbleUpon&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-twitter&quot;&gt;
			&lt;a href=&quot;http://twitter.com/home?status=StreamHitching+-+stream+wrapper+mini+framework+alpha+version+now+fully+PHPUnit+t%5B..%5D+-+http://bit.ly/cVOOwF&amp;source=shareaholic&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Tweet This!&quot;&gt;Tweet This!&lt;/a&gt;
		&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;/div&gt;
&lt;/div&gt;</content>
		<author>
			<name>Christian</name>
			<uri>http://test.ical.ly</uri>
		</author>
		<source>
			<title type="html">test.ical.ly &#187; phpUnit</title>
			<subtitle type="html">getting PHP by the balls</subtitle>
			<link rel="self" href="http://test.ical.ly/tags/phpunit/feed/atom/"/>
			<id>http://test.ical.ly/feed/atom/</id>
			<updated>2010-09-01T00:00:27+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">PHPUnit 3.5 Beta 1</title>
		<link href="http://sebastian-bergmann.de/archives/891-PHPUnit-3.5-Beta-1.html"/>
		<id>http://sebastian-bergmann.de/archives/891-guid.html</id>
		<updated>2010-06-08T08:20:00+00:00</updated>
		<content type="html">&lt;p&gt;To celebrate the 15th birthday of PHP, I have released PHPUnit 3.5 Beta 1 today. The refactoring towards components is a &quot;new feature&quot; that is already visible upon installation:&lt;/p&gt;&lt;dl&gt;&lt;dd&gt;&lt;small&gt;&lt;pre&gt;sb@vmware ~ % pear install phpunit/PHPUnit-beta
phpunit/PHPUnit can optionally use PHP extension &quot;dbus&quot;
downloading PHPUnit-3.5.0beta1.tgz ...
Starting to download PHPUnit-3.5.0beta1.tgz (105,588 bytes)
........................done: 105,588 bytes
downloading DbUnit-1.0.0beta1.tgz ...
Starting to download DbUnit-1.0.0beta1.tgz (38,209 bytes)
...done: 38,209 bytes
downloading File_Iterator-1.2.1.tgz ...
Starting to download File_Iterator-1.2.1.tgz (3,225 bytes)
...done: 3,225 bytes
downloading Text_Template-1.0.0.tgz ...
Starting to download Text_Template-1.0.0.tgz (2,493 bytes)
...done: 2,493 bytes
downloading PHP_CodeCoverage-1.0.0beta1.tgz ...
Starting to download PHP_CodeCoverage-1.0.0beta1.tgz (108,640 bytes)
...done: 108,640 bytes
downloading PHP_Timer-1.0.0.tgz ...
Starting to download PHP_Timer-1.0.0.tgz (2,536 bytes)
...done: 2,536 bytes
downloading PHPUnit_MockObject-1.0.0beta1.tgz ...
Starting to download PHPUnit_MockObject-1.0.0beta1.tgz (15,816 bytes)
...done: 15,816 bytes
downloading PHPUnit_Selenium-1.0.0beta1.tgz ...
Starting to download PHPUnit_Selenium-1.0.0beta1.tgz (15,298 bytes)
...done: 15,298 bytes
downloading PHP_TokenStream-1.0.0beta1.tgz ...
Starting to download PHP_TokenStream-1.0.0beta1.tgz (7,023 bytes)
...done: 7,023 bytes
install ok: channel://pear.phpunit.de/File_Iterator-1.2.1
install ok: channel://pear.phpunit.de/Text_Template-1.0.0
install ok: channel://pear.phpunit.de/PHP_Timer-1.0.0
install ok: channel://pear.phpunit.de/PHP_TokenStream-1.0.0beta1
install ok: channel://pear.phpunit.de/PHP_CodeCoverage-1.0.0beta1
install ok: channel://pear.phpunit.de/PHPUnit-3.5.0beta1
install ok: channel://pear.phpunit.de/DbUnit-1.0.0beta1
install ok: channel://pear.phpunit.de/PHPUnit_MockObject-1.0.0beta1
install ok: channel://pear.phpunit.de/PHPUnit_Selenium-1.0.0beta1&lt;/pre&gt;&lt;/small&gt;&lt;/dd&gt;&lt;/dl&gt;&lt;p&gt;Happy Birthday PHP! And have fun testing (with) PHPUnit 3.5!&lt;/p&gt;</content>
		<author>
			<name>Sebastian Bergmann</name>
			<email>nospam@example.com</email>
			<uri>http://sebastian-bergmann.de/</uri>
		</author>
		<source>
			<title type="html">Sebastian Bergmann - PHPUnit</title>
			<link rel="self" href="http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss"/>
			<id>http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss</id>
			<updated>2010-08-19T08:00:26+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">How many asserts should a PHPUnit test case have?</title>
		<link href="http://test.ical.ly/2010/06/07/how-many-asserts-should-a-phpunit-test-case-have/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=how-many-asserts-should-a-phpunit-test-case-have"/>
		<id>http://test.ical.ly/?p=976</id>
		<updated>2010-06-07T20:28:15+00:00</updated>
		<content type="html">&lt;p&gt;&lt;img class=&quot;alignleft size-medium wp-image-977&quot; title=&quot;case&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/06/case-300x178.jpg&quot; alt=&quot;case&quot; width=&quot;300&quot; height=&quot;178&quot; /&gt;This question came up &lt;a href=&quot;http://test.ical.ly/2010/06/07/unit-testing-php-stream-wrappers-with-phpunit/comment-page-1/#comment-636&quot;&gt;in the comments&lt;/a&gt; to &lt;a href=&quot;http://test.ical.ly/2010/06/07/unit-testing-php-stream-wrappers-with-phpunit/comment-page-1/&quot; target=&quot;_blank&quot;&gt;yesterdays post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The commenter &lt;em&gt;WC&lt;/em&gt; summed it up pretty well I think but I am going to summarise it anyway.&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-976&quot;&gt;&lt;/span&gt;I a lot of best practice books or blog posts you can read that only a single assertion is advised per test case.&lt;/p&gt;
&lt;p&gt;The reason is simple.&lt;/p&gt;
&lt;p&gt;A test case will return failed as soon as one of its assertions fails. The consequence of this is that any succeeding asserts are no longer executed so you wont know if they pass or fail until you fixed the first assertion.&lt;/p&gt;
&lt;p&gt;There are exceptions to this rule though.&lt;/p&gt;
&lt;p&gt;I just recently had to test a stream wrapper and one of the methods to test was &lt;em&gt;stream_stat()&lt;/em&gt; which is called by PHP in return of calling &lt;em&gt;fstat()&lt;/em&gt;.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;php&quot;&gt;  &lt;span&gt;public&lt;/span&gt; &lt;span&gt;function&lt;/span&gt; testFstat&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
  &lt;span&gt;&amp;#123;&lt;/span&gt;
    &lt;span&gt;$fh&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;fopen&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'r'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$stat&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;fstat&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$fh&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertType&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;PHPUnit_Framework_Constraint_IsType&lt;span&gt;::&lt;/span&gt;&lt;span&gt;TYPE_ARRAY&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;$stat&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'fstat &#8212; Gets information about a file using an open file pointer'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertTrue&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;array_key_exists&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'dev'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;$stat&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'fstat &#8212; Gets information about a file using an open file pointer'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertTrue&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;array_key_exists&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'ino'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;$stat&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'fstat &#8212; Gets information about a file using an open file pointer'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertTrue&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;array_key_exists&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'mode'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;$stat&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'fstat &#8212; Gets information about a file using an open file pointer'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertTrue&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;array_key_exists&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'nlink'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;$stat&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'fstat &#8212; Gets information about a file using an open file pointer'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertTrue&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;array_key_exists&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'uid'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;$stat&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'fstat &#8212; Gets information about a file using an open file pointer'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertTrue&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;array_key_exists&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'gid'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;$stat&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'fstat &#8212; Gets information about a file using an open file pointer'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertTrue&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;array_key_exists&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'rdev'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;$stat&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'fstat &#8212; Gets information about a file using an open file pointer'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertTrue&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;array_key_exists&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'size'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;$stat&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'fstat &#8212; Gets information about a file using an open file pointer'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertTrue&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;array_key_exists&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'atime'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;$stat&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'fstat &#8212; Gets information about a file using an open file pointer'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertTrue&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;array_key_exists&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'mtime'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;$stat&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'fstat &#8212; Gets information about a file using an open file pointer'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertTrue&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;array_key_exists&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'ctime'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;$stat&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'fstat &#8212; Gets information about a file using an open file pointer'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertTrue&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;array_key_exists&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'blksize'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;$stat&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'fstat &#8212; Gets information about a file using an open file pointer'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertTrue&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;array_key_exists&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'blocks'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;$stat&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'fstat &#8212; Gets information about a file using an open file pointer'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;fclose&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$fh&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This might not be the prettiest test case but you can see a lot of succeeding assertions.&lt;/p&gt;
&lt;p&gt;The reason why I think this is a valid exception to the otherwise reasonable rule is that all of these assertions test for a detail of a single operation.&lt;br /&gt;
Especially the &lt;em&gt;TYPE_ARRAY&lt;/em&gt; test would make no real sense alone it would just blow up the code.&lt;/p&gt;
&lt;p&gt;Any thoughts?&lt;/p&gt;


&lt;div class=&quot;shr-bookmarks shr-bookmarks-expand shr-bookmarks-bg-shr&quot;&gt;
&lt;ul class=&quot;socials&quot;&gt;
		&lt;li class=&quot;shr-delicious&quot;&gt;
			&lt;a href=&quot;http://delicious.com/post?url=http://test.ical.ly/2010/06/07/how-many-asserts-should-a-phpunit-test-case-have/&amp;title=How+many+asserts+should+a+PHPUnit+test+case+have%3F&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on del.icio.us&quot;&gt;Share this on del.icio.us&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-linkedin&quot;&gt;
			&lt;a href=&quot;http://www.linkedin.com/shareArticle?mini=true&amp;url=http://test.ical.ly/2010/06/07/how-many-asserts-should-a-phpunit-test-case-have/&amp;title=How+many+asserts+should+a+PHPUnit+test+case+have%3F&amp;summary=This%20question%20came%20up%20in%20the%20comments%20to%20yesterdays%20post.%0D%0A%0D%0AThe%20commenter%20WC%20summed%20it%20up%20pretty%20well%20I%20think%20but%20I%20am%20going%20to%20summarise%20it%20anyway.%0D%0A%0D%0AI%20a%20lot%20of%20best%20practice%20books%20or%20blog%20posts%20you%20can%20read%20that%20only%20a%20single%20assertion%20is%20advised%20per%20test%20case.%0D%0A%0D%0AThe%20reason%20is%20simple.%0D%0A%0D%0AA%20test&amp;source=test.ical.ly&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on LinkedIn&quot;&gt;Share this on LinkedIn&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-mail&quot;&gt;
			&lt;a href=&quot;mailto:?subject=%22How%20many%20asserts%20should%20a%20PHPUnit%20test%20case%20have%3F%22&amp;body=Link: http://test.ical.ly/2010/06/07/how-many-asserts-should-a-phpunit-test-case-have/ (sent via shareaholic)%0D%0A%0D%0A----%0D%0A This%20question%20came%20up%20in%20the%20comments%20to%20yesterdays%20post.%0D%0A%0D%0AThe%20commenter%20WC%20summed%20it%20up%20pretty%20well%20I%20think%20but%20I%20am%20going%20to%20summarise%20it%20anyway.%0D%0A%0D%0AI%20a%20lot%20of%20best%20practice%20books%20or%20blog%20posts%20you%20can%20read%20that%20only%20a%20single%20assertion%20is%20advised%20per%20test%20case.%0D%0A%0D%0AThe%20reason%20is%20simple.%0D%0A%0D%0AA%20test&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Email this to a friend?&quot;&gt;Email this to a friend?&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-misterwong&quot;&gt;
			&lt;a href=&quot;http://www.mister-wong.com/addurl/?bm_url=http://test.ical.ly/2010/06/07/how-many-asserts-should-a-phpunit-test-case-have/&amp;bm_description=How+many+asserts+should+a+PHPUnit+test+case+have%3F&amp;plugin=sexybookmarks&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Add this to Mister Wong&quot;&gt;Add this to Mister Wong&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-netvibes&quot;&gt;
			&lt;a href=&quot;http://www.netvibes.com/share?title=How+many+asserts+should+a+PHPUnit+test+case+have%3F&amp;url=http://test.ical.ly/2010/06/07/how-many-asserts-should-a-phpunit-test-case-have/&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Submit this to Netvibes&quot;&gt;Submit this to Netvibes&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-reddit&quot;&gt;
			&lt;a href=&quot;http://reddit.com/submit?url=http://test.ical.ly/2010/06/07/how-many-asserts-should-a-phpunit-test-case-have/&amp;title=How+many+asserts+should+a+PHPUnit+test+case+have%3F&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on Reddit&quot;&gt;Share this on Reddit&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-stumbleupon&quot;&gt;
			&lt;a href=&quot;http://www.stumbleupon.com/submit?url=http://test.ical.ly/2010/06/07/how-many-asserts-should-a-phpunit-test-case-have/&amp;title=How+many+asserts+should+a+PHPUnit+test+case+have%3F&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Stumble upon something good? Share it on StumbleUpon&quot;&gt;Stumble upon something good? Share it on StumbleUpon&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-twitter&quot;&gt;
			&lt;a href=&quot;http://twitter.com/home?status=How+many+asserts+should+a+PHPUnit+test+case+have%3F+-+http://bit.ly/c3GcK9&amp;source=shareaholic&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Tweet This!&quot;&gt;Tweet This!&lt;/a&gt;
		&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;/div&gt;
&lt;/div&gt;</content>
		<author>
			<name>Christian</name>
			<uri>http://test.ical.ly</uri>
		</author>
		<source>
			<title type="html">test.ical.ly &#187; phpUnit</title>
			<subtitle type="html">getting PHP by the balls</subtitle>
			<link rel="self" href="http://test.ical.ly/tags/phpunit/feed/atom/"/>
			<id>http://test.ical.ly/feed/atom/</id>
			<updated>2010-09-01T00:00:27+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Unit testing PHP Stream Wrappers with PHPUnit</title>
		<link href="http://test.ical.ly/2010/06/07/unit-testing-php-stream-wrappers-with-phpunit/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=unit-testing-php-stream-wrappers-with-phpunit"/>
		<id>http://test.ical.ly/?p=970</id>
		<updated>2010-06-07T03:10:59+00:00</updated>
		<content type="html">&lt;p&gt;&lt;img class=&quot;alignleft size-medium wp-image-972&quot; title=&quot;field-book-of-ponds-and-streams&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/06/field-book-of-ponds-and-streams-225x300.jpg&quot; alt=&quot;field-book-of-ponds-and-streams&quot; width=&quot;225&quot; height=&quot;300&quot; /&gt;In the last couple of months I have occupied myself a lot with unit testing. Once you get the hand of it it starts to feel natural and easy and you don&amp;#8217;t want to miss it any more. Testing rocks!&lt;/p&gt;
&lt;p&gt;Another thing I worked with are PHP streams which IMHO is one of the most underrated features of PHP.&lt;/p&gt;
&lt;p&gt;Naturally I want to test my stream wrappers with PHPUnit just as I would test everything else. But it&amp;#8217;s not that easy..&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-970&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;When you develop a software component you design it to be used and with your unit tests you simulate this usage as a warranty that your changes to the component won&amp;#8217;t break the code using it.&lt;/p&gt;
&lt;p&gt;With stream wrappers this becomes a bit tricky as you don&amp;#8217;t have an easy access to the code calling your component.&lt;/p&gt;
&lt;p&gt;For example you will most likely implement &lt;em&gt;stream_open()&lt;/em&gt; which is called internally by &lt;em&gt;fopen()&lt;/em&gt; and that&amp;#8217;s the difficulty.&lt;/p&gt;
&lt;p&gt;This is a part your stream wrapper:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;php&quot;&gt;  &lt;span&gt;public&lt;/span&gt; &lt;span&gt;function&lt;/span&gt; stream_open &lt;span&gt;&amp;#40;&lt;/span&gt; string &lt;span&gt;$path&lt;/span&gt; &lt;span&gt;,&lt;/span&gt; string &lt;span&gt;$mode&lt;/span&gt; &lt;span&gt;,&lt;/span&gt; int &lt;span&gt;$options&lt;/span&gt; &lt;span&gt;,&lt;/span&gt; string &lt;span&gt;&amp;amp;&lt;/span&gt;amp&lt;span&gt;;&lt;/span&gt;&lt;span&gt;$opened_path&lt;/span&gt; &lt;span&gt;&amp;#41;&lt;/span&gt;
  &lt;span&gt;&amp;#123;&lt;/span&gt;
    &lt;span&gt;..&lt;/span&gt;
    &lt;span&gt;// Returns TRUE on success or FALSE on failure.&lt;/span&gt;
  &lt;span&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And this will be the part of the code using it:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;php&quot;&gt;&lt;span&gt;..&lt;/span&gt;
&lt;span&gt;$fh&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;fopen&lt;/span&gt; &lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'yourprotocol://some/path/and/file.name'&lt;/span&gt; &lt;span&gt;,&lt;/span&gt; &lt;span&gt;'r'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;$context&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;..&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Usually I would attempt to test &lt;em&gt;stream_open()&lt;/em&gt; with a test like this:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;php&quot;&gt;  &lt;span&gt;public&lt;/span&gt; &lt;span&gt;function&lt;/span&gt; testStreamOpen&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
  &lt;span&gt;&amp;#123;&lt;/span&gt;
    &lt;span&gt;$wrapper&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; MyStreamWrapper&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertTrue&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$wrapper&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;stream_open&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'myprotocol://some/path/and/file.name'&lt;/span&gt; &lt;span&gt;,&lt;/span&gt; &lt;span&gt;'r'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But have you noticed that the signatures of &#160;&lt;em&gt;stream_open()&lt;/em&gt; and &lt;em&gt;fopen()&lt;/em&gt; is different after the second parameter?&lt;/p&gt;
&lt;p&gt;Somewhere within the C code of PHP the call to &lt;em&gt;fopen()&lt;/em&gt; will be implemented and eventually it will make a call to your &lt;em&gt;stream_open()&lt;/em&gt;. In the meantime it will have passed the context (which needs to be a public attribute of your stream wrapper and it will calculate some options and an opened path.&lt;/p&gt;
&lt;p&gt;Writing a test as I did above will probably work in most cases. But how can you be sure that every possible call to &lt;em&gt;fopen()&lt;/em&gt; is working well when you don&amp;#8217;t know what happens between the two methods?&lt;/p&gt;
&lt;p&gt;You could have a thorough look at the sources of the PHP binary of course and I won&amp;#8217;t stop you as this will be an interesting read. But I think an easier approach would be to change the unit test to something like this:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;php&quot;&gt;  &lt;span&gt;public&lt;/span&gt; &lt;span&gt;function&lt;/span&gt; testStreamOpen&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
  &lt;span&gt;&amp;#123;&lt;/span&gt;
    &lt;span&gt;stream_wrapper_register&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'myprotocol'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'MyStreamWrapper'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertNotFalse&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;fopen&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'yourprotocol://some/path/and/file.name'&lt;/span&gt; &lt;span&gt;,&lt;/span&gt; &lt;span&gt;'r'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertNotFalse&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;fopen&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'yourprotocol://some/path/and/file.name'&lt;/span&gt; &lt;span&gt;,&lt;/span&gt; &lt;span&gt;'w'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertNotFalse&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;fopen&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'yourprotocol://some/path/and/file.name'&lt;/span&gt; &lt;span&gt;,&lt;/span&gt; &lt;span&gt;'r'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;true&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertNotFalse&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;fopen&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'yourprotocol://some/path/and/file.name'&lt;/span&gt; &lt;span&gt;,&lt;/span&gt; &lt;span&gt;'r'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;stream_context_create&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;array&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'yourprotocol'&lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;array&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertFalse&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;fopen&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'yourprotocol://some/path/and/file.name'&lt;/span&gt; &lt;span&gt;,&lt;/span&gt; &lt;span&gt;'r'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;stream_context_create&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;array&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'yourprotocol'&lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;array&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;..&lt;/span&gt;
    &lt;span&gt;stream_wrapper_unregister&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'myprotocol'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So instead of testing your stream wrappers methods directly you test if all defined usage of your stream wrapper is functioning by calling the appropriate PHP filesystem functions.&lt;/p&gt;
&lt;p&gt;In my current case I have a stream wrapper that represents a single read only file. So I wrote tests for each PHP filesystem function that attempts to work on a file assuming that write access fails while read access passes.&lt;/p&gt;
&lt;p&gt;Additionally I wrote unit tests calling the stream wrapper methods directly just to make sure.&lt;/p&gt;


&lt;div class=&quot;shr-bookmarks shr-bookmarks-expand shr-bookmarks-bg-shr&quot;&gt;
&lt;ul class=&quot;socials&quot;&gt;
		&lt;li class=&quot;shr-delicious&quot;&gt;
			&lt;a href=&quot;http://delicious.com/post?url=http://test.ical.ly/2010/06/07/unit-testing-php-stream-wrappers-with-phpunit/&amp;title=Unit+testing+PHP+Stream+Wrappers+with+PHPUnit&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on del.icio.us&quot;&gt;Share this on del.icio.us&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-linkedin&quot;&gt;
			&lt;a href=&quot;http://www.linkedin.com/shareArticle?mini=true&amp;url=http://test.ical.ly/2010/06/07/unit-testing-php-stream-wrappers-with-phpunit/&amp;title=Unit+testing+PHP+Stream+Wrappers+with+PHPUnit&amp;summary=In%20the%20last%20couple%20of%20months%20I%20have%20occupied%20myself%20a%20lot%20with%20unit%20testing.%20Once%20you%20get%20the%20hand%20of%20it%20it%20starts%20to%20feel%20natural%20and%20easy%20and%20you%20don%27t%20want%20to%20miss%20it%20any%20more.%20Testing%20rocks%21%0D%0A%0D%0AAnother%20thing%20I%20worked%20with%20are%20PHP%20streams%20which%20IMHO%20is%20one%20of%20the%20most%20underrated%20features%20of%20PHP.%0D&amp;source=test.ical.ly&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on LinkedIn&quot;&gt;Share this on LinkedIn&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-mail&quot;&gt;
			&lt;a href=&quot;mailto:?subject=%22Unit%20testing%20PHP%20Stream%20Wrappers%20with%20PHPUnit%22&amp;body=Link: http://test.ical.ly/2010/06/07/unit-testing-php-stream-wrappers-with-phpunit/ (sent via shareaholic)%0D%0A%0D%0A----%0D%0A In%20the%20last%20couple%20of%20months%20I%20have%20occupied%20myself%20a%20lot%20with%20unit%20testing.%20Once%20you%20get%20the%20hand%20of%20it%20it%20starts%20to%20feel%20natural%20and%20easy%20and%20you%20don%27t%20want%20to%20miss%20it%20any%20more.%20Testing%20rocks%21%0D%0A%0D%0AAnother%20thing%20I%20worked%20with%20are%20PHP%20streams%20which%20IMHO%20is%20one%20of%20the%20most%20underrated%20features%20of%20PHP.%0D&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Email this to a friend?&quot;&gt;Email this to a friend?&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-misterwong&quot;&gt;
			&lt;a href=&quot;http://www.mister-wong.com/addurl/?bm_url=http://test.ical.ly/2010/06/07/unit-testing-php-stream-wrappers-with-phpunit/&amp;bm_description=Unit+testing+PHP+Stream+Wrappers+with+PHPUnit&amp;plugin=sexybookmarks&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Add this to Mister Wong&quot;&gt;Add this to Mister Wong&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-netvibes&quot;&gt;
			&lt;a href=&quot;http://www.netvibes.com/share?title=Unit+testing+PHP+Stream+Wrappers+with+PHPUnit&amp;url=http://test.ical.ly/2010/06/07/unit-testing-php-stream-wrappers-with-phpunit/&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Submit this to Netvibes&quot;&gt;Submit this to Netvibes&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-reddit&quot;&gt;
			&lt;a href=&quot;http://reddit.com/submit?url=http://test.ical.ly/2010/06/07/unit-testing-php-stream-wrappers-with-phpunit/&amp;title=Unit+testing+PHP+Stream+Wrappers+with+PHPUnit&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Share this on Reddit&quot;&gt;Share this on Reddit&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-stumbleupon&quot;&gt;
			&lt;a href=&quot;http://www.stumbleupon.com/submit?url=http://test.ical.ly/2010/06/07/unit-testing-php-stream-wrappers-with-phpunit/&amp;title=Unit+testing+PHP+Stream+Wrappers+with+PHPUnit&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Stumble upon something good? Share it on StumbleUpon&quot;&gt;Stumble upon something good? Share it on StumbleUpon&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;shr-twitter&quot;&gt;
			&lt;a href=&quot;http://twitter.com/home?status=Unit+testing+PHP+Stream+Wrappers+with+PHPUnit+-+http://bit.ly/bwmByd&amp;source=shareaholic&quot; rel=&quot;nofollow&quot; class=&quot;external&quot; title=&quot;Tweet This!&quot;&gt;Tweet This!&lt;/a&gt;
		&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;/div&gt;
&lt;/div&gt;</content>
		<author>
			<name>Christian</name>
			<uri>http://test.ical.ly</uri>
		</author>
		<source>
			<title type="html">test.ical.ly &#187; phpUnit</title>
			<subtitle type="html">getting PHP by the balls</subtitle>
			<link rel="self" href="http://test.ical.ly/tags/phpunit/feed/atom/"/>
			<id>http://test.ical.ly/feed/atom/</id>
			<updated>2010-09-01T00:00:27+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">PHP Temporary Streams</title>
		<link href="http://mikenaberezny.com/2008/10/17/php-temporary-streams/"/>
		<id>http://mikenaberezny.com/?p=156</id>
		<updated>2010-05-29T18:49:03+00:00</updated>
		<content type="html">&lt;p&gt;It&amp;#8217;s been a while since David Sklar &lt;a href=&quot;http://www.sklar.com/blog/archives/116-Let-a-thousand-string-concatenations-bloom.html&quot;&gt;called out&lt;/a&gt; to &lt;i&gt;let a thousand string concatenations bloom&lt;/i&gt;.  That discussion produced some entertaining suggestions for putting strings together such as using &lt;code&gt;preg_replace&lt;/code&gt; and calling out to MySQL with &lt;code&gt;SELECT CONCAT&lt;/code&gt;.  &lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s an approach that uses filesystem functions.  When combined with some lesser-known PHP streams functionality, it has several practical applications.&lt;/p&gt;
&lt;h4&gt;Opening Files for Reading and Writing&lt;/h4&gt;
&lt;p&gt;There are several modes for &lt;a href=&quot;http://www.php.net/fopen&quot;&gt;opening&lt;/a&gt; a file that will allow you to seek to arbitrary positions in the file and read or write at those positions.  One of the most frequently used of these modes is &lt;code&gt;w+&lt;/code&gt;, which the &lt;code&gt;tmpfile&lt;/code&gt; function uses automatically.&lt;/p&gt;
&lt;p&gt;We can repeatedly write, then rewind the pointer and read:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;php&quot;&gt;&lt;span&gt;$f&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;tmpfile&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;fwrite&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$f&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'foo'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;fwrite&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$f&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'bar'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;rewind&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$f&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;$contents&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;stream_get_contents&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$f&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;  &lt;span&gt;//=&amp;gt; &amp;quot;foobar&amp;quot;&lt;/span&gt;
&lt;span&gt;fclose&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$f&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When writing to the filesystem, the above provides yet another inefficient solution to David&amp;#8217;s exercise.  Now let&amp;#8217;s take it a bit further to see how this can be useful.&lt;/p&gt;
&lt;h4&gt;In-Memory Streams&lt;/h4&gt;
&lt;p&gt;PHP 5.1 introduced two new in-memory streams: &lt;code&gt;php://memory&lt;/code&gt; and &lt;code&gt;php://temp&lt;/code&gt;.  The &lt;code&gt;php://memory&lt;/code&gt; stream operates entirely in memory.  The &lt;code&gt;php://temp&lt;/code&gt; stream operates in memory until it reaches a given size, then transparently switches to the filesystem.  &lt;/p&gt;
&lt;p&gt;We can modify the above example to use the &lt;code&gt;php://memory&lt;/code&gt; stream instead of hitting the filesystem:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;php&quot;&gt;&lt;span&gt;$f&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;fopen&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'php://memory'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'w+'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;fwrite&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$f&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'foo'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;fwrite&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$f&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'bar'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;rewind&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$f&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;$contents&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;stream_get_contents&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$f&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;  &lt;span&gt;//=&amp;gt; &amp;quot;foobar&amp;quot;&lt;/span&gt;
&lt;span&gt;fclose&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$f&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Putting a string inside a fast temporary stream can be very useful.  For example, we can then &lt;a href=&quot;http://us2.php.net/manual/en/function.stream-filter-append.php&quot;&gt;attach filters&lt;/a&gt; to that stream.  &lt;/p&gt;
&lt;h4&gt;Testing&lt;/h4&gt;
&lt;p&gt;Temporary streams are also handy for testing.  There are some rather elaborate virtual file system libraries out there but many times a stream is all you need.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://framework.zend.com/manual/en/zend.log.html&quot;&gt;Zend_Log&lt;/a&gt; has a log handler for streams that accepts either a filename or a stream resource.  We can configure it with a &lt;code&gt;php://memory&lt;/code&gt; stream for testing:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;php&quot;&gt;&lt;span&gt;$f&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;fopen&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'php://memory'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'w+'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;$writer&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; Zend_Log_Writer_Stream&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$f&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;$logger&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; Zend_Log&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$writer&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Assuming your well-designed application has a convenient injection point for the logger instance, your test can pass it in before your test activates some action which should result in logging:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;php&quot;&gt;&lt;span&gt;$logger&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;crit&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'critical message worth testing'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When the action has completed, the test can rewind &lt;code&gt;$f&lt;/code&gt; and use it as a test spy.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;php&quot;&gt;&lt;span&gt;rewind&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$f&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;$contents&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;stream_get_contents&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$f&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertRegExp&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'/message worth testing/i'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;$contents&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;  &lt;span&gt;// PHPUnit&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Not surprisingly, my &lt;a href=&quot;http://framework.zend.com/svn/framework/standard/trunk/tests/Zend/Log/Writer/StreamTest.php&quot;&gt;unit tests&lt;/a&gt; for Zend_Log use this same technique.  &lt;/p&gt;
&lt;h4&gt;Application Usage&lt;/h4&gt;
&lt;p&gt;Not long ago, we built a custom &lt;a href=&quot;http://maintainable.com/case_studies/syneron_depot&quot;&gt;document storage system&lt;/a&gt; for a client.  One of its more interesting features is that it integrates with an internet fax service so users can select documents in the system and then fax them.  For each fax, the software automatically generates a cover page.&lt;/p&gt;
&lt;p&gt;To make the cover page, I first made a nice template using a drawing tool and then saved it in PDF format.  I then used &lt;a href=&quot;http://framework.zend.com/manual/en/zend.pdf.html&quot;&gt;Zend_Pdf&lt;/a&gt; to write over the template with dynamic content.  I first demonstrated this technique in &lt;a href=&quot;http://mikenaberezny.com/2006/05/02/zend-framework-tutorial-published/&quot;&gt;this article&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since the cover page is only used once (during transmission) and easy to regenerate, I don&amp;#8217;t save the output to the filesystem.  Instead, I create a &lt;code&gt;php://temp&lt;/code&gt; stream.  The instance method &lt;code&gt;Zend_Pdf-&amp;gt;render()&lt;/code&gt; writes the PDF output only to that stream, which is then rewound.  Functions like &lt;code&gt;stream_copy_to_stream&lt;/code&gt; or &lt;code&gt;fpassthru&lt;/code&gt; can then be used to send the final output where it needs to go, and the whole process normally never needs to use the disk.&lt;/p&gt;</content>
		<author>
			<name>Mike Naberezny</name>
			<uri>http://mikenaberezny.com</uri>
		</author>
		<source>
			<title type="html">Mike Naberezny &#187; phpunit</title>
			<link rel="self" href="http://mikenaberezny.com/tag/phpunit/feed/atom/"/>
			<id>http://mikenaberezny.com/feed/atom/</id>
			<updated>2010-09-02T23:00:25+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">OSCON 2008 Slides</title>
		<link href="http://mikenaberezny.com/2008/07/25/oscon-2008-slides/"/>
		<id>http://mikenaberezny.com/?p=214</id>
		<updated>2010-05-29T18:48:07+00:00</updated>
		<content type="html">&lt;p&gt;Slides from my two talks at OSCON 2008 are now available:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://mikenaberezny.com/talks/oscon08/integration_testing_php_apps.pdf&quot;&gt;Integration Testing PHP Applications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://mikenaberezny.com/talks/oscon08/supervisor_as_a_platform.pdf&quot;&gt;Supervisor as a Platform&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both talks were well attended had great audience participation.  Thanks to everyone that attended and I hope you enjoyed them.&lt;/p&gt;
&lt;p&gt;About seven people came up after the Integration Testing talk with good questions and feedback.  I think that 45 minutes was enough to provide good starting points for the topics covered but it was clear that these users were engaged and ready to dig into it more.  If I give this talk again, it is going to be in a tutorial format so we can get much deeper into the material and have some exercises.&lt;/p&gt;
&lt;p&gt;After my &lt;a href=&quot;http://supervisord.org&quot;&gt;Supervisor&lt;/a&gt; talk at the end of the day, I had the pleasure of going out to dinner with Roger Hoover and some other Supervisor users.  It&amp;#8217;s been very exciting to see Supervisor picking up traction over the past year.  Besides the work that Chris McDonough and I are doing, Supervisor is being used in several large architectures of companies whose names you know.  If you&amp;#8217;re using Supervisor and wouldn&amp;#8217;t mind us telling others about it, please contact me.&lt;/p&gt;</content>
		<author>
			<name>Mike Naberezny</name>
			<uri>http://mikenaberezny.com</uri>
		</author>
		<source>
			<title type="html">Mike Naberezny &#187; phpunit</title>
			<link rel="self" href="http://mikenaberezny.com/tag/phpunit/feed/atom/"/>
			<id>http://mikenaberezny.com/feed/atom/</id>
			<updated>2010-09-02T23:00:25+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Speaking at OSCON 2008</title>
		<link href="http://mikenaberezny.com/2008/04/02/speaking-at-oscon-2008/"/>
		<id>http://mikenaberezny.com/?p=103</id>
		<updated>2010-05-29T18:47:43+00:00</updated>
		<content type="html">&lt;p&gt;&lt;img src=&quot;http://mikenaberezny.com/wp-content/uploads/2008/04/oscon2008_banner_speaker_210x60.gif&quot; /&gt;The OSCON 2008 website has published its &lt;a href=&quot;http://en.oreilly.com/oscon2008/public/schedule/grid&quot;&gt;talk schedule&lt;/a&gt;.  I&amp;#8217;ll be giving two talks at OSCON this year; one on the &lt;a href=&quot;http://en.oreilly.com/oscon2008/public/schedule/topic/Python&quot;&gt;Python track&lt;/a&gt; and one on the &lt;a href=&quot;http://en.oreilly.com/oscon2008/public/schedule/topic/PHP&quot;&gt;PHP track&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Supervisor as a Platform&lt;/h4&gt;
&lt;p&gt;I will quickly introduce you to &lt;a href=&quot;http://supervisord.org&quot;&gt;Supervisor&lt;/a&gt; and the immediate benefits of running your server processes under it.  We will then dive into how applications written specifically for Supervisor can take advantage of it as a platform &amp;#8212; writing your own event listeners to observe Supervisor and the process lifecycle, controlling with XML-RPC, and extending the Supervisor core with your own Python extensions.  &lt;/p&gt;
&lt;p&gt;This will be an expanded version of the talk I gave with &lt;a href=&quot;http://plope.com&quot;&gt;Chris McDonough&lt;/a&gt; at PyCon 2008.  Since PyCon, there&amp;#8217;s been quite a few interesting developments in Supervisor like the ability to extend &lt;code&gt;supervisorctl&lt;/code&gt; and progress made on configuration reloading.  We&amp;#8217;ll touch on these as well, so if you attended the PyCon talk there will still be new and interesting material in this talk for you.&lt;/p&gt;
&lt;h4&gt;Integration Testing PHP Applications&lt;/h4&gt;
&lt;p&gt;While more PHP developers are recognizing the importance and benefits of unit testing, the uptake of PHP developers using automated integration or acceptance testing is relatively slow. This testing is equally crucial to maintaining the integrity of applications.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m going to help get you started testing at the application level with practical tips and source code.  We&amp;#8217;ll look at how to structure your HTML markup so it&amp;#8217;s more easily testable, making tests easier to write and maintain with CSS selectors, organizing your tests, and testing with or without a browser.  &lt;/p&gt;
&lt;p&gt;We write a lot of PHP applications with this kind of testing at &lt;a href=&quot;http://maintainable.com&quot;&gt;Maintainable&lt;/a&gt;.  Before the conference, we plan to release some open source PHP code to help you test that we&amp;#8217;ll cover in the talk as well.  I&amp;#8217;d also suggest you check out Sebastian Bergmann&amp;#8217;s &lt;a href=&quot;http://sebastian-bergmann.de/archives/763-PHPUnit-Tutorial-OSCON-2008.html&quot;&gt;tutorial session&lt;/a&gt; on PHPUnit&amp;#8217;s integration with Selenium RC.&lt;/p&gt;</content>
		<author>
			<name>Mike Naberezny</name>
			<uri>http://mikenaberezny.com</uri>
		</author>
		<source>
			<title type="html">Mike Naberezny &#187; phpunit</title>
			<link rel="self" href="http://mikenaberezny.com/tag/phpunit/feed/atom/"/>
			<id>http://mikenaberezny.com/feed/atom/</id>
			<updated>2010-09-02T23:00:25+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Best practice of PHPUnit testing a symfony 1.4 plugin</title>
		<link href="http://test.ical.ly/2010/04/26/best-practice-of-phpunit-testing-a-symfony-1-4-plugin/"/>
		<id>http://test.ical.ly/?p=659</id>
		<updated>2010-05-19T11:16:32+00:00</updated>
		<content type="html">&lt;p&gt;&lt;img class=&quot;alignleft size-medium wp-image-741&quot; title=&quot;escher-moebius&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/04/escher-moebius-134x300.gif&quot; alt=&quot;escher-moebius&quot; width=&quot;134&quot; height=&quot;300&quot; /&gt;I started this blog to occupy myself with topics like unit testing, continuous integration and code quality in general. As a subject for my studies I quickly released a symfony plugin (&lt;a title=&quot;sfImageTransformExtraPlugin&quot; href=&quot;http://www.symfony-project.org/plugins/sfImageTransformExtraPlugin&quot; target=&quot;_blank&quot;&gt;sfImageTransformExtraPlugin&lt;/a&gt;) that I already worked on for a while and decided to excercise all my learnings on it. So you can peek at the sources to see more details.&lt;/p&gt;
&lt;p&gt;As all the early posts of this blog were kept in German I am going to summarise the &lt;em&gt;best practice of PHPUnit testing a symfony 1.4 plugin&lt;/em&gt; in this post.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Of course I have to say that the term best practice refers to my current state of knowledge. &lt;img src=&quot;http://test.ical.ly/wp-includes/images/smilies/icon_smile.gif&quot; alt=&quot;:)&quot; class=&quot;wp-smiley&quot; /&gt; &lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-659&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Why PHPUnit?&lt;/h2&gt;
&lt;p&gt;Actually when I started this blog I was determined to use symfonys own lime unit test implementation because it is integrated and documented within the symfony documentation. But the more I worked with it the more I was put off by it.&lt;/p&gt;
&lt;p&gt;lime is ok for being run during development by the developer itself but it can not easily be used in continuous integration as it is not fully xUnit compliant and does not provide all infos you want to see there. lime is also very procedual and the more complex your application become the more spaghetti code you will have to maintain. And foremost lime is only used in the symfony world and learning it will not have any benefit for you in other projects.&lt;/p&gt;
&lt;p&gt;PHPUnit on the other hand is the de facto standard for PHP. It is object oriented as well as well documented and maintained and it is fully xUnit compliant thus can easily be integrated into your continuous integration workflow.&lt;/p&gt;
&lt;h2&gt;Prerequisites / Assumptions about your plugin&lt;/h2&gt;
&lt;p&gt;In the following I assume that you generated your plugin by running the symfony&#160;task&#160;&lt;em&gt;generate:plugin&lt;/em&gt; (provided by sfTaskExtraPlugin) and that you did not change the files and directories inside your plugins &lt;em&gt;/test&lt;/em&gt; directory.&lt;/p&gt;
&lt;p&gt;This is important as there are many files that were generated for you that may look curious to you but will make a lot more sense once you learned how to use them.&lt;/p&gt;
&lt;p&gt;Of course these files were created with lime in mind and in the following I will show you what you need to change to use the same structure with PHPUnit.&lt;/p&gt;
&lt;h2&gt;Bootstrapping&lt;/h2&gt;
&lt;p&gt;In your plugins &lt;em&gt;/test/bootstrap&lt;/em&gt; you will find a script for bootstrapping for your unit tests &lt;em&gt;unit.php&lt;/em&gt;.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;php&quot;&gt;// /plugins/myTestPlugin/test/bootstrap/unit.php
&lt;span&gt;&amp;lt;?php&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;if&lt;/span&gt; &lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;isset&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$_SERVER&lt;/span&gt;&lt;span&gt;&amp;#91;&lt;/span&gt;&lt;span&gt;'SYMFONY'&lt;/span&gt;&lt;span&gt;&amp;#93;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&lt;span&gt;&amp;#123;&lt;/span&gt;
  throw &lt;span&gt;new&lt;/span&gt; RuntimeException&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'Could not find symfony core libraries.'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;require_once&lt;/span&gt; &lt;span&gt;$_SERVER&lt;/span&gt;&lt;span&gt;&amp;#91;&lt;/span&gt;&lt;span&gt;'SYMFONY'&lt;/span&gt;&lt;span&gt;&amp;#93;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;'/autoload/sfCoreAutoload.class.php'&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
sfCoreAutoload&lt;span&gt;::&lt;/span&gt;&lt;span&gt;register&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;$configuration&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; sfProjectConfiguration&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;dirname&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;__FILE__&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;'/../fixtures/project'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;require_once&lt;/span&gt; &lt;span&gt;$configuration&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;getSymfonyLibDir&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;'/vendor/lime/lime.php'&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;function&lt;/span&gt; myTestPlugin_autoload_again&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$class&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&lt;span&gt;&amp;#123;&lt;/span&gt;
  &lt;span&gt;$autoload&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; sfSimpleAutoload&lt;span&gt;::&lt;/span&gt;&lt;span&gt;getInstance&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;$autoload&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;reload&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;return&lt;/span&gt; &lt;span&gt;$autoload&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;autoload&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$class&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;&amp;#125;&lt;/span&gt;
&lt;span&gt;spl_autoload_register&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'myTestPlugin_autoload_again'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;if&lt;/span&gt; &lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;file_exists&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$config&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;dirname&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;__FILE__&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;'/../../config/myTestPluginConfiguration.class.php'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&lt;span&gt;&amp;#123;&lt;/span&gt;
  &lt;span&gt;require_once&lt;/span&gt; &lt;span&gt;$config&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;$plugin_configuration&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; myTestPluginConfiguration&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$configuration&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;dirname&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;__FILE__&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;'/../..'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'myTestPlugin'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;&amp;#125;&lt;/span&gt;
&lt;span&gt;else&lt;/span&gt;
&lt;span&gt;&amp;#123;&lt;/span&gt;
  &lt;span&gt;$plugin_configuration&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; sfPluginConfigurationGeneric&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$configuration&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;dirname&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;__FILE__&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;'/../..'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'myTestPlugin'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There are two things to notice here:&lt;/p&gt;
&lt;ol start=&quot;1&quot;&gt;
&lt;li&gt;&lt;strong&gt;The use of &lt;code&gt;$_SERVER['SYMFONY']&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When executing unit tests you have to tell the bootstrap where to look for the symfony core libraries. For lime this is actually done by the symfony test tasks but for PHPUnit we don&amp;#8217;t have a task available so we need to run the following command first (only once per console session).&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;sh&quot;&gt;$ export SYMFONY=&amp;quot;/absolute/path/to/lib/vendor/symfony/lib&amp;quot;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I will explain the reason behind this in a moment.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;strong&gt;The project configuration is looaded from a fixture project&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you have a look at your plugins &lt;em&gt;/test/fixtures/project&lt;/em&gt; directory you will recognise a complete symfony project just like you run &lt;em&gt;generate:project&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This is going to be your test environment.&lt;/p&gt;
&lt;p&gt;The reason for both of these two features is this:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;
The whole point of a symfony plugin is to be reusable and to be reusable it needs to be as project independant as possible.&lt;br /&gt;
Therefor it will not be unit testet in a project where the project developers can easily create situations where your tests will fail but in a fixture project you as a plugin developer can completely control.&lt;/p&gt;
&lt;p&gt;And because this fixture project is included in your project we don&amp;#8217;t want to also include the whole symfony code.&lt;br /&gt;
But a symfony plugin will always have at least one dependancy and that is towards symfony itself, so we have to make the location of it known to our plugin before running the tests.
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Now for PHPUnit we need to remove the following line from the code above.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;13
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;php&quot;&gt;&lt;span&gt;require_once&lt;/span&gt; &lt;span&gt;$configuration&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;getSymfonyLibDir&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;'/vendor/lime/lime.php'&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The purpose of this bootstrap file is to create the environment our plugin expects. So if all of your plugins functionalities need an instance of sfContext you would create it here or if they would all depend on the database you would create a connection here as well.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;But remember there should be as few dependencies as possible!&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;How to write your test cases?&lt;/h2&gt;
&lt;p&gt;This is the easies part of all. Just refer to the PHPUnit documentation and see how to write the tests themselves and add everything to classes like this:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
10
11
12
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;php&quot;&gt;// /test/unit/lib/yourPluginClassTest.php
&lt;span&gt;&amp;lt;?php&lt;/span&gt;
&lt;span&gt;require_once&lt;/span&gt; &lt;span&gt;dirname&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;__FILE__&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;'/../bootstrap/unit.php'&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;span&gt;require_once&lt;/span&gt; &lt;span&gt;'PHPUnit/Framework.php'&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;class&lt;/span&gt; yourPluginClassTest &lt;span&gt;extends&lt;/span&gt; PHPUnit_Framework_TestCase
&lt;span&gt;&amp;#123;&lt;/span&gt;
  &lt;span&gt;public&lt;/span&gt; &lt;span&gt;function&lt;/span&gt; testYourMethod&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
  &lt;span&gt;&amp;#123;&lt;/span&gt;
    &lt;span&gt;// .. implement your test here&lt;/span&gt;
  &lt;span&gt;&amp;#125;&lt;/span&gt;
&lt;span&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The above example will test your method &lt;code&gt;yourPluginClass::yourMethod()&lt;/code&gt; so you see the conventions of appending &amp;#8220;Test&amp;#8221; to the class and prepending &amp;#8220;test&amp;#8221; to the methods your going to test.&lt;/p&gt;
&lt;p&gt;I found it a good practice to organise my test cases the same way as the tested classes.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;sh&quot;&gt;For example:
/lib/routing/yourOwnRoute.class.php (classname: yourOwnRoute)
would be tested in:
/test/unit/lib/routing/yourOwnRouteTest.php (classname: yourOwnRouteTest)&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Another good practice is to have one test case per class so each of your classes has exactly one test class.&lt;/p&gt;
&lt;p&gt;You can run your test case like this.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;sh&quot;&gt;$ phpunit /test/unit/lib/routing/yourOwnRouteTest.php&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2&gt;How to write a test suite?&lt;/h2&gt;
&lt;p&gt;Often you want to run all your test cases at once. In fact for continuous integration purposes this is always the case. This can be achieved using a PHPUnit test suite that can run multiple test cases.&lt;/p&gt;
&lt;p&gt;A good naming convention is to create such a suite in the /test directory of your plugin and to call it like you called you plugin.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;php&quot;&gt;// /test/yourPluginTests.php
&lt;span&gt;&amp;lt;?php&lt;/span&gt;
&lt;span&gt;class&lt;/span&gt; yourPluginTests
&lt;span&gt;&amp;#123;&lt;/span&gt;
  &lt;span&gt;public&lt;/span&gt; static &lt;span&gt;function&lt;/span&gt; suite&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
  &lt;span&gt;&amp;#123;&lt;/span&gt;
    &lt;span&gt;global&lt;/span&gt; &lt;span&gt;$configuration&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;$plugin_configuration&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$suite&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; PHPUnit_Framework_TestSuite&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'yourPlugin'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;// loading plugin configurations&lt;/span&gt;
    &lt;span&gt;$configuration&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; ProjectConfiguration&lt;span&gt;::&lt;/span&gt;&lt;span&gt;getActive&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$pluginConfig&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;$configuration&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;getPluginConfiguration&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'yourPlugin'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;// instantiate a fake symfony unit test task to retrieve all connected tests for this plugin&lt;/span&gt;
    &lt;span&gt;$task&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; sfTestUnitTask&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$configuration&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;getEventDispatcher&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; sfFormatter&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$event&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; sfEvent&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$task&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'task.test.filter_test_files'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;array&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'arguments'&lt;/span&gt; &lt;span&gt;=&amp;gt;&lt;/span&gt; &lt;span&gt;array&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'name'&lt;/span&gt; &lt;span&gt;=&amp;gt;&lt;/span&gt; &lt;span&gt;array&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'options'&lt;/span&gt; &lt;span&gt;=&amp;gt;&lt;/span&gt; &lt;span&gt;array&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$files&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;$pluginConfig&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;filterTestFiles&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$event&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;array&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$suite&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;addTestFiles&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$files&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;return&lt;/span&gt; &lt;span&gt;$suite&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;&amp;#125;&lt;/span&gt;
&lt;span&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In this example I collected all test cases from the fixture project just like the symfony test task for lime does it. This is very convenient as you don&amp;#8217;t have to manually add new test cases. Refer to the &lt;a href=&quot;http://www.phpunit.de/manual/3.0/en/organizing-test-suites.html&quot; target=&quot;_blank&quot;&gt;AllTests section of the PHPUnit documentation&lt;/a&gt; for further details of a test suite.&lt;/p&gt;
&lt;p&gt;Next we need to make all our test cases known to the fixture project by editing the ProjectConfiguration class.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
10
11
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;php&quot;&gt;// taken from http://trac.symfony-project.org/browser/plugins/sfImageTransformExtraPlugin/trunk/test/fixtures/project/config/ProjectConfiguration.class.php
&lt;span&gt;&amp;lt;?php&lt;/span&gt;
&lt;span&gt;class&lt;/span&gt; ProjectConfiguration &lt;span&gt;extends&lt;/span&gt; sfProjectConfiguration
&lt;span&gt;&amp;#123;&lt;/span&gt;
  &lt;span&gt;// ...&lt;/span&gt;
&amp;nbsp;
  &lt;span&gt;public&lt;/span&gt; &lt;span&gt;function&lt;/span&gt; setupPlugins&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
  &lt;span&gt;&amp;#123;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;pluginConfigurations&lt;/span&gt;&lt;span&gt;&amp;#91;&lt;/span&gt;&lt;span&gt;'sfImageTransformExtraPlugin'&lt;/span&gt;&lt;span&gt;&amp;#93;&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;connectTests&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;&amp;#125;&lt;/span&gt;
&lt;span&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now you can run all your test cases like this.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;sh&quot;&gt;$ phpunit /test/yourPluginTests.php&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2&gt;The fixture project&lt;/h2&gt;
&lt;p&gt;I already mentioned the dependency towards symfony but there is more. There is also the dependency of your plugin towards being properly installed.&lt;br /&gt;
This dependency has to be reflected in the fixture project.&lt;/p&gt;
&lt;p&gt;For example if you have any schema defined for Doctrine or Propel then the classes generated from these schema will be generated outside your plugin except for the classes prefixed with &amp;#8220;Plugin&amp;#8221;. So you have to create these generated classes inside of the fixture project as well.&lt;br /&gt;
&lt;strong&gt;Make sure not to modify these classes they have to be absolutely pristine!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If your plugin needs an application youn have to create one in the fixtrue project and if certain settings in the app.yml or setting.yml or elsewhere are mandatory you will have to create them in the fixture project as well.&lt;/p&gt;
&lt;p&gt;Just be aware that you don&amp;#8217;t try to fix anything by only adding more to the fixture project. There should be as few changes to it as possible and all changes you have made should be properly documented as they are necessary for anybody who wants to use your plugin.&lt;/p&gt;
&lt;h2&gt;Dependencies to other plugins&lt;/h2&gt;
&lt;p&gt;Sometimes your plugin will depend on the existence of other plugins. For &lt;em&gt;sfImageTransformExtraPlugin&lt;/em&gt; this was the case as it required &lt;em&gt;sfImageTransformPlugin&lt;/em&gt; to be installed. In your fixture project this can be solved by editing the ProjectConfiguration class.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;php&quot;&gt;// taken from http://trac.symfony-project.org/browser/plugins/sfImageTransformExtraPlugin/trunk/test/fixtures/project/config/ProjectConfiguration.class.php
&lt;span&gt;&amp;lt;?php&lt;/span&gt;
&lt;span&gt;class&lt;/span&gt; ProjectConfiguration &lt;span&gt;extends&lt;/span&gt; sfProjectConfiguration
&lt;span&gt;&amp;#123;&lt;/span&gt;
  &lt;span&gt;public&lt;/span&gt; &lt;span&gt;function&lt;/span&gt; setup&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
  &lt;span&gt;&amp;#123;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;setPlugins&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;array&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'sfImageTransformExtraPlugin'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'sfImageTransformPlugin'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'sfDoctrinePlugin'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;setPluginPath&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'sfImageTransformExtraPlugin'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;dirname&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;__FILE__&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;'/../../../..'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;setPluginPath&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'sfImageTransformPlugin'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;dirname&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;__FILE__&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;'/../../../../../sfImageTransformPlugin'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
  &lt;span&gt;// ...&lt;/span&gt;
&lt;span&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This expects &lt;em&gt;sfImageTransformPlugin&lt;/em&gt; to be located right next to &lt;em&gt;sfImageTransformExtraPlugin&lt;/em&gt; which comes in handy if integrated with continuous integration services.&lt;/p&gt;
&lt;h2&gt;What to test?&lt;/h2&gt;
&lt;p&gt;For quite some time I kept asking this question. My answer is this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Don&amp;#8217;t test module code!&lt;/strong&gt; Module code in this case means actions or components. They have far too many dependencies in symfony 1.x and they should be very slim anyway. Test them with functional tests.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Don&amp;#8217;t test tests!&lt;/strong&gt; This should be self explaining really.. &lt;img src=&quot;http://test.ical.ly/wp-includes/images/smilies/icon_wink.gif&quot; alt=&quot;;)&quot; class=&quot;wp-smiley&quot; /&gt; &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test everything else!&lt;/strong&gt; This leaves you with the &lt;code&gt;/lib&lt;/code&gt; and &lt;code&gt;/config&lt;/code&gt; folders only.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And to keep a good overview you should create a coverage report from time to time. Using the following configuration file I use to create mine.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;xml&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;lt;?xml&lt;/span&gt; &lt;span&gt;version&lt;/span&gt;=&lt;span&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt; &lt;span&gt;encoding&lt;/span&gt;=&lt;span&gt;&amp;quot;UTF-8&amp;quot;&lt;/span&gt;&lt;span&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;&lt;span&gt;&amp;lt;phpunit&lt;/span&gt; &lt;span&gt;backupGlobals&lt;/span&gt;=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;         &lt;span&gt;backupStaticAttributes&lt;/span&gt;=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;         &lt;span&gt;colors&lt;/span&gt;=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;         &lt;span&gt;convertErrorsToExceptions&lt;/span&gt;=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;         &lt;span&gt;convertNoticesToExceptions&lt;/span&gt;=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;         &lt;span&gt;convertWarningsToExceptions&lt;/span&gt;=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;         &lt;span&gt;processIsolation&lt;/span&gt;=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;         &lt;span&gt;stopOnFailure&lt;/span&gt;=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;         &lt;span&gt;syntaxCheck&lt;/span&gt;=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&amp;nbsp;
  &lt;span&gt;&lt;span&gt;&amp;lt;testsuites&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;testsuite&lt;/span&gt; &lt;span&gt;name&lt;/span&gt;=&lt;span&gt;&amp;quot;yourPlugin Suite&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;directory&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;./test/unit/&lt;span&gt;&lt;span&gt;&amp;lt;/directory&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;/testsuite&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;/testsuites&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&amp;nbsp;
  &lt;span&gt;&lt;span&gt;&amp;lt;filter&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;whitelist&lt;/span&gt; &lt;span&gt;addUncoveredFilesFromWhitelist&lt;/span&gt;=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;directory&lt;/span&gt; &lt;span&gt;suffix&lt;/span&gt;=&lt;span&gt;&amp;quot;.class.php&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;./lib/&lt;span&gt;&lt;span&gt;&amp;lt;/directory&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;directory&lt;/span&gt; &lt;span&gt;suffix&lt;/span&gt;=&lt;span&gt;&amp;quot;.class.php&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;./config/&lt;span&gt;&lt;span&gt;&amp;lt;/directory&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;/whitelist&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;/filter&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/phpunit&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Change into the root directory of your plugin to execute phpunit other wise the relative paths will not work as they are relative to the execution dir not the configuration file!&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;PHPUnit testing of symfony plugins is tricky as it is not documented anywhere. But it is still very possible and once you got the hang of it feels very natural.&lt;/p&gt;
&lt;p&gt;I hope this will help some of you t get started.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Things like mocking database connections or all the hazzle with sfContext might be subject to another post.&lt;br /&gt;
&lt;/em&gt;&lt;/p&gt;


&lt;!-- Begin SexyBookmarks Menu Code --&gt;
&lt;div class=&quot;sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-german&quot;&gt;
&lt;ul class=&quot;socials&quot;&gt;
		&lt;li class=&quot;sexy-twitter&quot;&gt;
			&lt;a href=&quot;http://twitter.com/home?status=Best+practice+of+PHPUnit+testing+a+symfony+1.4+plugin+-+http://b2l.me/rak3j+(via+@testically)&amp;source=shareaholic&quot; rel=&quot;nofollow&quot; title=&quot;Twittere diesen Artikel!&quot;&gt;Twittere diesen Artikel!&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-delicious&quot;&gt;
			&lt;a href=&quot;http://delicious.com/post?url=http://test.ical.ly/2010/04/26/best-practice-of-phpunit-testing-a-symfony-1-4-plugin/&amp;title=Best+practice+of+PHPUnit+testing+a+symfony+1.4+plugin&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei del.icio.us&quot;&gt;Empfehle diesen Artikel bei del.icio.us&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-reddit&quot;&gt;
			&lt;a href=&quot;http://reddit.com/submit?url=http://test.ical.ly/2010/04/26/best-practice-of-phpunit-testing-a-symfony-1-4-plugin/&amp;title=Best+practice+of+PHPUnit+testing+a+symfony+1.4+plugin&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Reddit&quot;&gt;Empfehle diesen Artikel bei Reddit&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-stumbleupon&quot;&gt;
			&lt;a href=&quot;http://www.stumbleupon.com/submit?url=http://test.ical.ly/2010/04/26/best-practice-of-phpunit-testing-a-symfony-1-4-plugin/&amp;title=Best+practice+of+PHPUnit+testing+a+symfony+1.4+plugin&quot; rel=&quot;nofollow&quot; title=&quot;Bei StumbleUpon einstellen&quot;&gt;Bei StumbleUpon einstellen&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-linkedin&quot;&gt;
			&lt;a href=&quot;http://www.linkedin.com/shareArticle?mini=true&amp;url=http://test.ical.ly/2010/04/26/best-practice-of-phpunit-testing-a-symfony-1-4-plugin/&amp;title=Best+practice+of+PHPUnit+testing+a+symfony+1.4+plugin&amp;summary=I%20started%20this%20blog%20to%20occupy%20myself%20with%20topics%20like%20unit%20testing%2C%20continuous%20integration%20and%20code%20quality%20in%20general.%20As%20a%20subject%20for%20my%20studies%20I%20quickly%20released%20a%20symfony%20plugin%20%28sfImageTransformExtraPlugin%29%20that%20I%20already%20worked%20on%20for%20a%20while%20and%20decided%20to%20excercise%20all%20my%20learnings%20on%20it.%20&amp;source=test.ical.ly&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei LinkedIn&quot;&gt;Empfehle diesen Artikel bei LinkedIn&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-technorati&quot;&gt;
			&lt;a href=&quot;http://technorati.com/faves?add=http://test.ical.ly/2010/04/26/best-practice-of-phpunit-testing-a-symfony-1-4-plugin/&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Technorati&quot;&gt;Empfehle diesen Artikel bei Technorati&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-facebook&quot;&gt;
			&lt;a href=&quot;http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://test.ical.ly/2010/04/26/best-practice-of-phpunit-testing-a-symfony-1-4-plugin/&amp;t=Best+practice+of+PHPUnit+testing+a+symfony+1.4+plugin&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Facebook&quot;&gt;Empfehle diesen Artikel bei Facebook&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-google&quot;&gt;
			&lt;a href=&quot;http://test.ical.ly/2010/04/26/best-practice-of-phpunit-testing-a-symfony-1-4-plugin/&quot; rel=&quot;nofollow&quot; title=&quot;&quot;&gt;&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-misterwong&quot;&gt;
			&lt;a href=&quot;http://www.mister-wong.de/addurl/?bm_url=http://test.ical.ly/2010/04/26/best-practice-of-phpunit-testing-a-symfony-1-4-plugin/&amp;bm_description=Best+practice+of+PHPUnit+testing+a+symfony+1.4+plugin&amp;plugin=sexybookmarks&quot; rel=&quot;nofollow&quot; title=&quot;F&#252;ge hinzu zu Mister Wong&quot;&gt;F&#252;ge hinzu zu Mister Wong&lt;/a&gt;
		&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;!-- End SexyBookmarks Menu Code --&gt;</content>
		<author>
			<name>Christian</name>
			<uri>http://test.ical.ly</uri>
		</author>
		<source>
			<title type="html">test.ical.ly &#187; phpUnit</title>
			<subtitle type="html">getting PHP by the balls</subtitle>
			<link rel="self" href="http://test.ical.ly/tags/phpunit/feed/atom/"/>
			<id>http://test.ical.ly/feed/atom/</id>
			<updated>2010-09-01T00:00:27+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">PHP-Magazin Artikel zum Thema Softwaremetriken</title>
		<link href="http://www.manuel-pichler.de/archives/89-PHP-Magazin-Artikel-zum-Thema-Softwaremetriken.html"/>
		<id>http://www.manuel-pichler.de/archives/89-guid.html</id>
		<updated>2010-05-12T07:04:12+00:00</updated>
		<content type="html">&lt;p&gt;
  &lt;em&gt;This blog post is in German as the mentioned article was published in German.&lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;
In der heute erschienenen Ausgabe &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2366&amp;entry_id=89&quot; title=&quot;http://it-republik.de/php/php-magazin-ausgaben/LinkedIn-vs.-Xing-000396.html&quot;&gt;4.10&lt;/a&gt; des &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2367&amp;entry_id=89&quot; title=&quot;http://it-republik.de/php/php-magazin/&quot;&gt;PHP Magazins&lt;/a&gt; ist auch ein Artikel von mir enthalten, und wie sollte es wohl anders sein *Trommelwirbel*, besch&#228;ftigt der sich mit dem Thema &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2368&amp;entry_id=89&quot; title=&quot;http://de.wikipedia.org/wiki/Softwaremetrik&quot;&gt;Softwaremetriken&lt;/a&gt; &lt;img src=&quot;http://www.manuel-pichler.de/templates/default/img/emoticons/smile.png&quot; alt=&quot;:-)&quot; class=&quot;emoticon&quot; /&gt; In diesem Artikel gibt es eine sehr ausf&#252;hrliche Einf&#252;hrung in die Thematik, mit eine Reihe von praktischen Beispielen und den daraus ableitbaren Aussagen &#252;ber den untersuchten Quelltext.
&lt;/p&gt;

&lt;p&gt;
&#220;ber Kommentare, Anregungen und Kritik rund um den Artikel w&#252;rde ich mich sehr freuen. Und sollte euch der Artikel gefallen haben, empfehle ich die Internationale &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2369&amp;entry_id=89&quot; title=&quot;http://phpconference.com&quot;&gt;PHP Conference 2010&lt;/a&gt;, die vom 30. Mai bis 2. Juni in Berlin stattfindet, an der ich teilnehmen und zwei Vortr&#228;ge halten werden.
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2370&amp;entry_id=89&quot; title=&quot;http://it-republik.de/konferenzen/ext_scripts/v2/php/sessions-popup.php?module=ipc2010se&amp;id=13448&quot;&gt;Von Continuous Integration zu Continuous Deployment&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2371&amp;entry_id=89&quot; title=&quot;http://it-republik.de/konferenzen/ext_scripts/v2/php/sessions-popup.php?module=ipc2010se&amp;id=13450&quot;&gt;Statische Codeanalyse wirklich effektiv nutzen&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
		<author>
			<name>Manuel Pichler</name>
			<email>nospam@example.com</email>
			<uri>http://www.manuel-pichler.de/</uri>
		</author>
		<source>
			<title type="html">Manuel Pichler - phpundercontrol</title>
			<subtitle type="html">Trust is good, (phpUnder)Control is better.</subtitle>
			<link rel="self" href="http://manuel-pichler.de/feeds/categories/10-phpundercontrol.rss"/>
			<id>http://manuel-pichler.de/feeds/categories/10-phpundercontrol.rss</id>
			<updated>2010-06-10T11:00:28+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Artikel zum Thema Softwaremetriken</title>
		<link href="http://www.manuel-pichler.de/archives/88-Artikel-zum-Thema-Softwaremetriken.html"/>
		<id>http://www.manuel-pichler.de/archives/88-guid.html</id>
		<updated>2010-05-12T07:04:12+00:00</updated>
		<content type="html">&lt;p&gt;
  &lt;em&gt;This blog post is in German as the mentioned article was published in German.&lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;
In der heute erschienenen Ausgabe &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2360&amp;entry_id=88&quot; title=&quot;http://it-republik.de/php/php-magazin-ausgaben/LinkedIn-vs.-Xing-000396.html&quot;&gt;4.10&lt;/a&gt; des &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2361&amp;entry_id=88&quot; title=&quot;http://it-republik.de/php/php-magazin/&quot;&gt;PHP Magazins&lt;/a&gt; ist auch ein Artikel von mir enthalten, und wie sollte es wohl anders sein *Trommelwirbel*, besch&#228;ftigt der sich mit dem Thema &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2362&amp;entry_id=88&quot; title=&quot;http://de.wikipedia.org/wiki/Softwaremetrik&quot;&gt;Softwaremetriken&lt;/a&gt; &lt;img src=&quot;http://www.manuel-pichler.de/templates/default/img/emoticons/smile.png&quot; alt=&quot;:-)&quot; class=&quot;emoticon&quot; /&gt; In diesem Artikel gibt es eine sehr ausf&#252;hrliche Einf&#252;hrung in die Thematik, mit eine Reihe von praktischen Beispielen und den daraus ableitbaren Aussagen &#252;ber den untersuchten Quelltext.
&lt;/p&gt;

&lt;p&gt;
&#220;ber Kommentare, Anregungen und Kritik rund um den Artikel w&#252;rde ich mich sehr freuen. Und sollte euch der Artikel gefallen haben, empfehle ich die Internationale &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2363&amp;entry_id=88&quot; title=&quot;http://phpconference.com&quot;&gt;PHP Conference 2010&lt;/a&gt;, die vom 30. Mai bis 2. Juni in Berlin stattfindet, an der ich teilnehmen und zwei Vortr&#228;ge halten werden.
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2364&amp;entry_id=88&quot; title=&quot;http://it-republik.de/konferenzen/ext_scripts/v2/php/sessions-popup.php?module=ipc2010se&amp;id=13448&quot;&gt;Von Continuous Integration zu Continuous Deployment&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2365&amp;entry_id=88&quot; title=&quot;http://it-republik.de/konferenzen/ext_scripts/v2/php/sessions-popup.php?module=ipc2010se&amp;id=13450&quot;&gt;Statische Codeanalyse wirklich effektiv nutzen&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
		<author>
			<name>Manuel Pichler</name>
			<email>nospam@example.com</email>
			<uri>http://www.manuel-pichler.de/</uri>
		</author>
		<source>
			<title type="html">Manuel Pichler - phpundercontrol</title>
			<subtitle type="html">Trust is good, (phpUnder)Control is better.</subtitle>
			<link rel="self" href="http://manuel-pichler.de/feeds/categories/10-phpundercontrol.rss"/>
			<id>http://manuel-pichler.de/feeds/categories/10-phpundercontrol.rss</id>
			<updated>2010-06-10T11:00:28+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Preorder the PHP QA Book now</title>
		<link href="http://nohn.net/blog/view/id/preorder-the-php-qa-book-now"/>
		<id>http://nohn.net/blog/view/id/preorder-the-php-qa-book-now</id>
		<updated>2010-05-09T08:43:00+00:00</updated>
		<content type="html">&lt;div&gt;&lt;p&gt;
  You may want to preorder the &lt;a href=&quot;http://qualityassuranceinphpprojects.com/&quot;&gt;PHP QA Book&lt;/a&gt; now!
&lt;/p&gt;
&lt;p&gt;
  German Edition:
&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;a href=&quot;http://www.amazon.de/gp/product/3446419233/php-21&quot;&gt;Softwarequalit&#228;t
    in PHP-Projekten @ amazon.de&lt;/a&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  English Edition:
&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;a href=&quot;http://www.amazon.com/Real-World-Developing-High-Quality-Frameworks-Applications/dp/0470872497/php-21&quot;&gt;
    Real-World Solutions for Developing High-Quality PHP Frameworks
    and Applications @ amazon.com&lt;/a&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;a href=&quot;http://www.amazon.ca/Real-World-Developing-High-Quality-Frameworks-Applications/dp/0470872497/&quot;&gt;
    Real-World Solutions for Developing High-Quality PHP Frameworks
    and Applications @ amazon.ca&lt;/a&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;a href=&quot;http://www.amazon.co.uk/Real-World-Developing-High-Quality-Frameworks-Applications/dp/0470872497/php-21&quot;&gt;
    Real-World Solutions for Developing High-Quality PHP Frameworks
    and Applications @ amazon.co.uk&lt;/a&gt;
  &lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;</content>
		<author>
			<name>Sebastian Nohn</name>
			<uri>http://nohn.net/blog/</uri>
		</author>
		<source>
			<title type="html">Sebastian Nohn - Blog</title>
			<subtitle type="html">.</subtitle>
			<link rel="self" href="http://nohn.net/blog/feed/tag/phpunit/type/atom"/>
			<id>http://www.nohn.net/blog/</id>
			<updated>2010-09-02T23:00:24+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Running PHPUnit tests for your symfony plugin in Hudson</title>
		<link href="http://test.ical.ly/2010/05/04/running-phpunit-tests-for-your-symfony-plugin-in-hudson/"/>
		<id>http://test.ical.ly/?p=812</id>
		<updated>2010-05-04T07:01:46+00:00</updated>
		<content type="html">&lt;p&gt;&lt;img class=&quot;alignleft size-full wp-image-813&quot; title=&quot;PHPUnit-testing-symfony-in-Hudson&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/05/PHPUnit-testing-symfony-in-Hudson.png&quot; alt=&quot;PHPUnit-testing-symfony-in-Hudson&quot; width=&quot;224&quot; height=&quot;135&quot; /&gt;Yesterday I wrote about &lt;a title=&quot;Running PHPUnit tests for your symfony plugin in phpUnderControl&quot; href=&quot;http://test.ical.ly/2010/05/04/running-phpunit-tests-for-your-symfony-plugin-in-hudson/&quot; target=&quot;_blank&quot;&gt;setting up a symfony plugin project in phpUnderControl&lt;/a&gt;. However so far I&amp;#8217;ve been using Hudson as my Continuous Integration server.&#160;So before comparing the two I will explain how to achieve yesterdays setup using Hudson.&lt;span id=&quot;more-812&quot;&gt;&lt;/span&gt;I assume that you have a running Hudson installation ready.&lt;/p&gt;
&lt;p&gt;Hudson is &amp;#8211; as you will notice &amp;#8211; a web dialog driven tool. You can of course edit the underlying configuration files (mostly XML) but I never experienced the need as the web interface is just as powerful.&lt;/p&gt;
&lt;h2&gt;Creating the project&lt;/h2&gt;
&lt;p&gt;In Hudson projects are called jobs. You create one by clicking on &amp;#8220;&lt;em&gt;New Job&lt;/em&gt;&amp;#8220;.&lt;/p&gt;
&lt;div id=&quot;attachment_817&quot; class=&quot;wp-caption alignnone&quot;&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/05/hudson-new-job.jpg&quot;&gt;&lt;img class=&quot;size-full wp-image-817  &quot; title=&quot;hudson-new-job&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/05/hudson-new-job.jpg&quot; alt=&quot;hudson-new-job&quot; width=&quot;468&quot; height=&quot;209&quot; /&gt;&lt;/a&gt;&lt;p class=&quot;wp-caption-text&quot;&gt;Hudson dialog: New Job&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;What we want is a &lt;em&gt;free-style software project&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This will directly lead us to the Job Configuration dialog.&lt;/p&gt;
&lt;h2&gt;Checking out the sources&lt;/h2&gt;
&lt;p&gt;In the Source Code Management section of the Job Configuration dialog we select Subversion for our version control system (There is a Git plugin for Hudson available) and configure the three sources for symfony, sfImageTransformPlugin and sfImageTransformExtraPlugin.&lt;/p&gt;
&lt;div id=&quot;attachment_820&quot; class=&quot;wp-caption alignnone&quot;&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/05/hudson-job-configuration.jpg&quot;&gt;&lt;img class=&quot;size-full wp-image-820 &quot; title=&quot;hudson-job-configuration&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/05/hudson-job-configuration.jpg&quot; alt=&quot;Hudson dialog: Job Configuration&quot; width=&quot;468&quot; height=&quot;364&quot; /&gt;&lt;/a&gt;&lt;p class=&quot;wp-caption-text&quot;&gt;Hudson dialog: Job Configuration&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;This is self explaining really.&lt;/p&gt;
&lt;h2&gt;Preparing the build&lt;/h2&gt;
&lt;p&gt;Next we want the project to be build whenever there is a commit to one of the sources.&lt;/p&gt;
&lt;div id=&quot;attachment_821&quot; class=&quot;wp-caption alignnone&quot;&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/05/hudson-job-configuration-2.jpg&quot;&gt;&lt;img class=&quot;size-full wp-image-821 &quot; title=&quot;hudson-job-configuration-2&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/05/hudson-job-configuration-2.jpg&quot; alt=&quot;Hudson dialog: Job Configuration&quot; width=&quot;468&quot; height=&quot;154&quot; /&gt;&lt;/a&gt;&lt;p class=&quot;wp-caption-text&quot;&gt;Hudson dialog: Job Configuration&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;The syntax for the schedule is cronjob like. In this example Subversion will be polled every 15 minutes.&lt;/p&gt;
&lt;h2&gt;Running the tests&lt;/h2&gt;
&lt;p&gt;Now we have to configure everything for Hudson to know how to run the PHPUnit tests. For this we need to add a build step.&lt;/p&gt;
&lt;div id=&quot;attachment_822&quot; class=&quot;wp-caption alignnone&quot;&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/05/hudson-job-configuration-3.jpg&quot;&gt;&lt;img class=&quot;size-full wp-image-822 &quot; title=&quot;hudson-job-configuration-3&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/05/hudson-job-configuration-3.jpg&quot; alt=&quot;Hudson dialog: Job Configuration&quot; width=&quot;468&quot; height=&quot;40&quot; /&gt;&lt;/a&gt;&lt;p class=&quot;wp-caption-text&quot;&gt;Hudson dialog: Job Configuration&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;There are several ways to do this, some are build-in such as using ant scripts while some require a plugin like using a phing script.&lt;/p&gt;
&lt;p&gt;I found it easiest to use a shell command. For this you have to select &lt;em&gt;Execute shell&lt;/em&gt; from the dropdown.&lt;/p&gt;
&lt;div id=&quot;attachment_823&quot; class=&quot;wp-caption alignnone&quot;&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/05/hudson-job-configuration-4.jpg&quot;&gt;&lt;img class=&quot;size-full wp-image-823 &quot; title=&quot;hudson-job-configuration-4&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/05/hudson-job-configuration-4.jpg&quot; alt=&quot;Hudson dialog: Job Configuration&quot; width=&quot;468&quot; height=&quot;120&quot; /&gt;&lt;/a&gt;&lt;p class=&quot;wp-caption-text&quot;&gt;Hudson dialog: Job Configuration&lt;/p&gt;&lt;/div&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;sh&quot;&gt;export SYMFONY=$WORKSPACE/symfony
mkdir -p $WORKSPACE/logs
rm -rf $WORKSPACE/logs/*
cd $WORKSPACE/sfImageTransformExtraPlugin/
phpunit --log-xml=$WORKSPACE/logs/phpunit-results.xml test/sfImageTransformExtraPluginTests.php&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As you can see this is a small bash script that sets the SYMFONY variable prepares a location for the PHPUnit report and runs the test suite.&lt;/p&gt;
&lt;p&gt;The last thing we need to do is to tell Hudson what to do with the test results.&lt;/p&gt;
&lt;p&gt;For this we add a &lt;em&gt;Post-build Action&lt;/em&gt; and select PHPUnit.&lt;/p&gt;
&lt;div id=&quot;attachment_825&quot; class=&quot;wp-caption alignnone&quot;&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/05/hudson-job-configuration-5.jpg&quot;&gt;&lt;img class=&quot;size-full wp-image-825&quot; title=&quot;hudson-job-configuration-5&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/05/hudson-job-configuration-5.jpg&quot; alt=&quot;hudson-job-configuration-5&quot; width=&quot;468&quot; height=&quot;122&quot; /&gt;&lt;/a&gt;&lt;p class=&quot;wp-caption-text&quot;&gt;Hudson dialog: Job Configuration&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;Then we enter the location of the result XML generated by the previous build step.&lt;/p&gt;
&lt;div id=&quot;attachment_826&quot; class=&quot;wp-caption alignnone&quot;&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/05/hudson-job-configuration-6.jpg&quot;&gt;&lt;img class=&quot;size-full wp-image-826 &quot; title=&quot;hudson-job-configuration-6&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/05/hudson-job-configuration-6.jpg&quot; alt=&quot;Hudson dialog: Job Configuration&quot; width=&quot;468&quot; height=&quot;83&quot; /&gt;&lt;/a&gt;&lt;p class=&quot;wp-caption-text&quot;&gt;Hudson dialog: Job Configuration&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;For this last step you will need the &lt;a title=&quot;Hudson xUnit Plugin&quot; href=&quot;http://wiki.hudson-ci.org/display/HUDSON/xUnit+Plugin&quot; target=&quot;_blank&quot;&gt;xUnit Plugin&lt;/a&gt; installed.&lt;/p&gt;
&lt;p&gt;If you don&amp;#8217;t have xUnit Plugin installed already you can save your settings now and edit them later (browse to your Job and click on &lt;em&gt;Configure&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;Now save the dialog and you will be presented with your Jobs webpage.&lt;/p&gt;
&lt;div id=&quot;attachment_827&quot; class=&quot;wp-caption alignnone&quot;&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/05/hudson-job-page.jpg&quot;&gt;&lt;img class=&quot;size-full wp-image-827 &quot; title=&quot;hudson-job-page&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/05/hudson-job-page.jpg&quot; alt=&quot;Hudson job page&quot; width=&quot;468&quot; height=&quot;228&quot; /&gt;&lt;/a&gt;&lt;p class=&quot;wp-caption-text&quot;&gt;Hudson job page&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;Now click on &lt;em&gt;Build Now&lt;/em&gt; to start the first build. This might take a while as the first checkout of symfony is quite big.&lt;/p&gt;
&lt;p&gt;The successful build should look like this:&lt;/p&gt;
&lt;div id=&quot;attachment_828&quot; class=&quot;wp-caption alignnone&quot;&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/05/hudson-successful-build.jpg&quot;&gt;&lt;img class=&quot;size-full wp-image-828 &quot; title=&quot;hudson-successful-build&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/05/hudson-successful-build.jpg&quot; alt=&quot;Hudson: Successful first build&quot; width=&quot;468&quot; height=&quot;298&quot; /&gt;&lt;/a&gt;&lt;p class=&quot;wp-caption-text&quot;&gt;Hudson: Successful first build&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;Now you can of course start adding more features such as pDepend, Cloverage reports, Mess Detection, Copy and Paste Detection and many more but for this post we&amp;#8217;re done. &lt;img src=&quot;http://test.ical.ly/wp-includes/images/smilies/icon_wink.gif&quot; alt=&quot;;)&quot; class=&quot;wp-smiley&quot; /&gt; &lt;/p&gt;


&lt;!-- Begin SexyBookmarks Menu Code --&gt;
&lt;div class=&quot;sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-german&quot;&gt;
&lt;ul class=&quot;socials&quot;&gt;
		&lt;li class=&quot;sexy-twitter&quot;&gt;
			&lt;a href=&quot;http://twitter.com/home?status=Running+PHPUnit+tests+for+your+symfony+plugin+in+Hudson+-+http://bit.ly/ctZjKJ+(via+@testically)&amp;source=shareaholic&quot; rel=&quot;nofollow&quot; title=&quot;Twittere diesen Artikel!&quot;&gt;Twittere diesen Artikel!&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-delicious&quot;&gt;
			&lt;a href=&quot;http://delicious.com/post?url=http://test.ical.ly/2010/05/04/running-phpunit-tests-for-your-symfony-plugin-in-hudson/&amp;title=Running+PHPUnit+tests+for+your+symfony+plugin+in+Hudson&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei del.icio.us&quot;&gt;Empfehle diesen Artikel bei del.icio.us&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-reddit&quot;&gt;
			&lt;a href=&quot;http://reddit.com/submit?url=http://test.ical.ly/2010/05/04/running-phpunit-tests-for-your-symfony-plugin-in-hudson/&amp;title=Running+PHPUnit+tests+for+your+symfony+plugin+in+Hudson&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Reddit&quot;&gt;Empfehle diesen Artikel bei Reddit&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-stumbleupon&quot;&gt;
			&lt;a href=&quot;http://www.stumbleupon.com/submit?url=http://test.ical.ly/2010/05/04/running-phpunit-tests-for-your-symfony-plugin-in-hudson/&amp;title=Running+PHPUnit+tests+for+your+symfony+plugin+in+Hudson&quot; rel=&quot;nofollow&quot; title=&quot;Bei StumbleUpon einstellen&quot;&gt;Bei StumbleUpon einstellen&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-linkedin&quot;&gt;
			&lt;a href=&quot;http://www.linkedin.com/shareArticle?mini=true&amp;url=http://test.ical.ly/2010/05/04/running-phpunit-tests-for-your-symfony-plugin-in-hudson/&amp;title=Running+PHPUnit+tests+for+your+symfony+plugin+in+Hudson&amp;summary=Yesterday%20I%20wrote%20about%20setting%20up%20a%20symfony%20plugin%20project%20in%20phpUnderControl.%20However%20so%20far%20I%27ve%20been%20using%20Hudson%20as%20my%20Continuous%20Integration%20server.%C2%A0So%20before%20comparing%20the%20two%20I%20will%20explain%20how%20to%20achieve%20yesterdays%20setup%20using%20Hudson.I%20assume%20that%20you%20have%20a%20running%20Hudson%20installation%20rea&amp;source=test.ical.ly&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei LinkedIn&quot;&gt;Empfehle diesen Artikel bei LinkedIn&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-technorati&quot;&gt;
			&lt;a href=&quot;http://technorati.com/faves?add=http://test.ical.ly/2010/05/04/running-phpunit-tests-for-your-symfony-plugin-in-hudson/&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Technorati&quot;&gt;Empfehle diesen Artikel bei Technorati&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-facebook&quot;&gt;
			&lt;a href=&quot;http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://test.ical.ly/2010/05/04/running-phpunit-tests-for-your-symfony-plugin-in-hudson/&amp;t=Running+PHPUnit+tests+for+your+symfony+plugin+in+Hudson&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Facebook&quot;&gt;Empfehle diesen Artikel bei Facebook&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-google&quot;&gt;
			&lt;a href=&quot;http://test.ical.ly/2010/05/04/running-phpunit-tests-for-your-symfony-plugin-in-hudson/&quot; rel=&quot;nofollow&quot; title=&quot;&quot;&gt;&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-misterwong&quot;&gt;
			&lt;a href=&quot;http://www.mister-wong.de/addurl/?bm_url=http://test.ical.ly/2010/05/04/running-phpunit-tests-for-your-symfony-plugin-in-hudson/&amp;bm_description=Running+PHPUnit+tests+for+your+symfony+plugin+in+Hudson&amp;plugin=sexybookmarks&quot; rel=&quot;nofollow&quot; title=&quot;F&#252;ge hinzu zu Mister Wong&quot;&gt;F&#252;ge hinzu zu Mister Wong&lt;/a&gt;
		&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;!-- End SexyBookmarks Menu Code --&gt;</content>
		<author>
			<name>Christian</name>
			<uri>http://test.ical.ly</uri>
		</author>
		<source>
			<title type="html">test.ical.ly &#187; phpUnit</title>
			<subtitle type="html">getting PHP by the balls</subtitle>
			<link rel="self" href="http://test.ical.ly/tags/phpunit/feed/atom/"/>
			<id>http://test.ical.ly/feed/atom/</id>
			<updated>2010-09-01T00:00:27+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Running PHPUnit tests for your symfony plugin in phpUnderControl</title>
		<link href="http://test.ical.ly/2010/05/03/running-phpunit-tests-for-your-symfony-plugin-in-phpundercontrol/"/>
		<id>http://test.ical.ly/?p=791</id>
		<updated>2010-05-02T16:45:21+00:00</updated>
		<content type="html">&lt;p&gt;&lt;img class=&quot;alignleft size-full wp-image-794&quot; title=&quot;PHPUnit-testing-symfony-in-phpUnderControl&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/04/PHPUnit-testing-symfony-in-phpUnderControl.png&quot; alt=&quot;PHPUnit-testing-symfony-in-phpUnderControl&quot; width=&quot;224&quot; height=&quot;135&quot; /&gt;As I&amp;#8217;ve just started to look into phpUnderControl again I thought why not try to setup a project for testing sfImageTransformExtraPlugin running all the PHPUnit tests that &lt;a href=&quot;http://test.ical.ly/2010/04/26/best-practice-of-phpunit-testing-a-symfony-1-4-plugin/&quot;&gt;I wrote about&lt;/a&gt; last week.&lt;/p&gt;
&lt;p&gt;So the goal is to setup a phpuc project for a single plugin but with all dependencies (symfony itself) provided. This was a bit tricky so here we go!&lt;span id=&quot;more-791&quot;&gt;&lt;/span&gt;The first thing I have to say is that although I frequently link to&lt;a title=&quot;Setting up phpUnderControl on Gentoo Linux&quot; href=&quot;http://blog.tjeu.be/2009/setting-up-phpundercontrol-on-gentoo-linux/&quot; target=&quot;_blank&quot;&gt; Andries Seutens&lt;/a&gt; for installing phpUnderControl for the subject of this post it is not recommended to create a project by running $ phpuc project ..! With this post I will follow the phpuc&#160;&lt;a title=&quot;phpUnderControl Documentation - Getting started&quot; href=&quot;http://www.phpundercontrol.org/documentation/getting-started.html&quot; target=&quot;_blank&quot;&gt;getting started&lt;/a&gt; guide instead.&lt;/p&gt;
&lt;h2&gt;Creating the project&lt;/h2&gt;
&lt;p&gt;First we need a project directory.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;sh&quot;&gt;$ mkdir /path/to/cruisecontrol/projects/yourProjectName&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next we need a very basic ant &lt;code&gt;build.xml&lt;/code&gt; file.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;xml&quot;&gt;// /path/to/cruisecontrol/projects/yourProjectName/build.xml
&lt;span&gt;&lt;span&gt;&amp;lt;?xml&lt;/span&gt; &lt;span&gt;version&lt;/span&gt;=&lt;span&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt; &lt;span&gt;encoding&lt;/span&gt;=&lt;span&gt;&amp;quot;UTF-8&amp;quot;&lt;/span&gt;&lt;span&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;project&lt;/span&gt; &lt;span&gt;name&lt;/span&gt;=&lt;span&gt;&amp;quot;yourProjectName&amp;quot;&lt;/span&gt; &lt;span&gt;basedir&lt;/span&gt;=&lt;span&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;&lt;span&gt;&amp;lt;/project&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now CruiseControl must be told about this new project in its &lt;code&gt;config.xml&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;xml&quot;&gt;// /path/to/cruisecontrol/config.xml
&lt;span&gt;&lt;span&gt;&amp;lt;?xml&lt;/span&gt; &lt;span&gt;version&lt;/span&gt;=&lt;span&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt; &lt;span&gt;encoding&lt;/span&gt;=&lt;span&gt;&amp;quot;UTF-8&amp;quot;&lt;/span&gt;&lt;span&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;cruisecontrol&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;project&lt;/span&gt; &lt;span&gt;name&lt;/span&gt;=&lt;span&gt;&amp;quot;yourProjectName&amp;quot;&lt;/span&gt; &lt;span&gt;buildafterfailed&lt;/span&gt;=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&amp;nbsp;
  &lt;span&gt;&lt;span&gt;&amp;lt;/project&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/cruisecontrol&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That the very basic project setup. Next we will need the subject.&lt;/p&gt;
&lt;h2&gt;Checkout the sources&lt;/h2&gt;
&lt;p&gt;First we need to create a &lt;code&gt;sources&lt;/code&gt; folder for the new project.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;sh&quot;&gt;$ mkdir /path/to/cruisecontrol/projects/yourProjectName/source&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There we checkout the source of our symfony plugin.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;sh&quot;&gt;// in /path/to/cruisecontrol/projects/yourProjectName/source/
$ svn co http://svn.symfony-project.org/plugins/sfImageTransformExtraPlugin/trunk sfImageTransformExtraPlugin&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This alone will not do as there are dependencies that are not included in the plugin. The most important one being symfony itself so we have to check that out as well.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;sh&quot;&gt;// in /path/to/cruisecontrol/projects/yourProjectName/source/
$ svn co http://svn.symfony-project.org/branches/1.4/ symfony&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For &lt;code&gt;sfImageTransformExtraPlugin&lt;/code&gt; there is an additional dependency towards &lt;code&gt;sfImageTransformPlugin&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;sh&quot;&gt;// in /path/to/cruisecontrol/projects/yourProjectName/source/
$ svn co http://svn.symfony-project.org/plugins/sfImageTransformPlugin/trunk sfImageTransformPlugin&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So now we have three fresh copies of the two plugins and symfony.&lt;/p&gt;
&lt;h2&gt;Preparing the build&lt;/h2&gt;
&lt;p&gt;Before every build we want to update all the sources to test against the latest commits. For this we edit the &lt;code&gt;build.xml&lt;/code&gt; again and add the following.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;3
4
5
6
7
8
9
10
11
12
13
14
15
16
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;xml&quot;&gt;// /path/to/cruisecontrol/projects/yourProjectName/build.xml
...
  &lt;span&gt;&lt;span&gt;&amp;lt;target&lt;/span&gt; &lt;span&gt;name&lt;/span&gt;=&lt;span&gt;&amp;quot;checkout&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;exec&lt;/span&gt; &lt;span&gt;executable&lt;/span&gt;=&lt;span&gt;&amp;quot;svn&amp;quot;&lt;/span&gt; &lt;span&gt;dir&lt;/span&gt;=&lt;span&gt;&amp;quot;${basedir}/source/symfony&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;arg&lt;/span&gt; &lt;span&gt;line&lt;/span&gt;=&lt;span&gt;&amp;quot;up&amp;quot;&lt;/span&gt; &lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;/exec&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;exec&lt;/span&gt; &lt;span&gt;executable&lt;/span&gt;=&lt;span&gt;&amp;quot;svn&amp;quot;&lt;/span&gt; &lt;span&gt;dir&lt;/span&gt;=&lt;span&gt;&amp;quot;${basedir}/source/sfImageTransformPlugin&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;arg&lt;/span&gt; &lt;span&gt;line&lt;/span&gt;=&lt;span&gt;&amp;quot;up&amp;quot;&lt;/span&gt; &lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;/exec&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;exec&lt;/span&gt; &lt;span&gt;executable&lt;/span&gt;=&lt;span&gt;&amp;quot;svn&amp;quot;&lt;/span&gt; &lt;span&gt;dir&lt;/span&gt;=&lt;span&gt;&amp;quot;${basedir}/source/sfImageTransformExtraPlugin&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;arg&lt;/span&gt; &lt;span&gt;line&lt;/span&gt;=&lt;span&gt;&amp;quot;up&amp;quot;&lt;/span&gt; &lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;/exec&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;/target&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
...&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The above will run svn up on all three working copies. You can varify this by running the following.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;sh&quot;&gt;// in /path/to/cruisecontrol/projects/yourProjectName/
$ ../../apache-ant-1.7.0/bin/ant checkout
Buildfile: build.xml
&amp;nbsp;
&amp;lt;pre lang=&amp;quot;sh&amp;quot;&amp;gt;
checkout:
     [exec] ...
...
&amp;nbsp;
BUILD SUCCESSFUL
Total time: 17 seconds&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2&gt;Running the tests&lt;/h2&gt;
&lt;p&gt;Before we run the tests we have to create a logs folder to store the build results and we also want a coverage folder to store our coverage reports for the build.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;sh&quot;&gt;// in /path/to/cruisecontrol/projects/yourProjectName/
$ mkdir -p build/{logs,coverage}&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we can add a new target to the build.xml.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;xml&quot;&gt;// in /path/to/cruisecontrol/projects/yourProjectName/build.xml
...
  &lt;span&gt;&lt;span&gt;&amp;lt;target&lt;/span&gt; &lt;span&gt;name&lt;/span&gt;=&lt;span&gt;&amp;quot;phpunit&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;exec&lt;/span&gt; &lt;span&gt;executable&lt;/span&gt;=&lt;span&gt;&amp;quot;phpunit&amp;quot;&lt;/span&gt; &lt;span&gt;dir&lt;/span&gt;=&lt;span&gt;&amp;quot;${basedir}/source/sfImageTransformExtraPlugin&amp;quot;&lt;/span&gt; &lt;span&gt;failonerror&lt;/span&gt;=&lt;span&gt;&amp;quot;on&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;env&lt;/span&gt; &lt;span&gt;key&lt;/span&gt;=&lt;span&gt;&amp;quot;SYMFONY&amp;quot;&lt;/span&gt; &lt;span&gt;value&lt;/span&gt;=&lt;span&gt;&amp;quot;${basedir}/source/symfony/lib&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;arg&lt;/span&gt; &lt;span&gt;line&lt;/span&gt;=&lt;span&gt;&amp;quot;--log-xml ${basedir}/build/logs/phpunit.xml&lt;/span&gt;
&lt;span&gt;                 --log-pmd ${basedir}/build/logs/phpunit.pmd.xml&lt;/span&gt;
&lt;span&gt;                 --log-metrics ${basedir}/build/logs/phpunit.metrics.xml&lt;/span&gt;
&lt;span&gt;                 --coverage-clover ${basedir}/build/logs/phpunit.coverage.xml&lt;/span&gt;
&lt;span&gt;                 --coverage-html ${basedir}/build/coverage&lt;/span&gt;
&lt;span&gt;                 sfImageTransformExtraPluginTests&lt;/span&gt;
&lt;span&gt;                 test/sfImageTransformExtraPluginTests.php&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;/exec&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;/target&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
...&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All this is more or less copied from the getting started page linked above except for the paths and this on line.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;16
17
18
19
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;xml&quot;&gt;// in /path/to/cruisecontrol/projects/yourProjectName/build.xml
...
      &lt;span&gt;&lt;span&gt;&amp;lt;env&lt;/span&gt; &lt;span&gt;key&lt;/span&gt;=&lt;span&gt;&amp;quot;SYMFONY&amp;quot;&lt;/span&gt; &lt;span&gt;value&lt;/span&gt;=&lt;span&gt;&amp;quot;${basedir}/source/symfony/lib&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
...&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This line does the same as &lt;code&gt;$ export SYMFONY=/path/to/cruisecontrol/projects/yourProjectName/source/symfony/lib&lt;/code&gt; and is needed for the testing bootstrap explained &lt;a href=&quot;http://test.ical.ly/2010/04/26/best-practice-of-phpunit-testing-a-symfony-1-4-plugin/&quot;&gt;here&lt;/a&gt; to find the symfony library.&lt;/p&gt;
&lt;p&gt;Of course all this can be tested again.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;sh&quot;&gt;// in /path/to/cruisecontrol/projects/yourProjectName/
$ ../../apache-ant-1.7.0/bin/ant phpunit
Buildfile: build.xml
&amp;nbsp;
phpunit:
     [exec] PHPUnit 3.3.1 by Sebastian Bergmann.
     [exec]
     [exec] .........................................................S.. 60 / 72
     [exec] ............
     [exec]
     [exec] Time: 33 seconds
     [exec]
     [exec] OK, but incomplete or skipped tests!
     [exec] Tests: 72, Assertions: 92, Skipped: 1.
     [exec]
     [exec] Writing code coverage data to XML file, this may take a moment.
     [exec]
     [exec] Writing metrics report XML file, this may take a moment.
     [exec]
     [exec] Writing violations report XML file, this may take a moment.
     [exec]
     [exec] Generating code coverage report, this may take a moment.
&amp;nbsp;
BUILD SUCCESSFUL
Total time: 47 seconds&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2&gt;Activating the targets&lt;/h2&gt;
&lt;p&gt;The two targets above now need to be triggered. This is done by the build target which can be dependant on other targets.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;3
4
5
6
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;xml&quot;&gt;// in /path/to/cruisecontrol/projects/yourProjectName/build.xml
...
  &lt;span&gt;&lt;span&gt;&amp;lt;target&lt;/span&gt; &lt;span&gt;name&lt;/span&gt;=&lt;span&gt;&amp;quot;build&amp;quot;&lt;/span&gt; &lt;span&gt;depends&lt;/span&gt;=&lt;span&gt;&amp;quot;checkout,phpunit&amp;quot;&lt;/span&gt; &lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
...&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;Configuring CruiseControl to build your project&lt;/h2&gt;
&lt;p&gt;Of course now cruisecontrol needs to be told about the details of the build so we edit the &lt;code&gt;config.xml&lt;/code&gt; again.&lt;/p&gt;
&lt;p&gt;First we need to include the required plugins in this case its for Subversion.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;4
5
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;xml&quot;&gt;// in /path/to/cruisecontrol/config.xml
 &lt;span&gt;&lt;span&gt;&amp;lt;plugin&lt;/span&gt; &lt;span&gt;name&lt;/span&gt;=&lt;span&gt;&amp;quot;svn&amp;quot;&lt;/span&gt; &lt;span&gt;classname&lt;/span&gt;=&lt;span&gt;&amp;quot;net.sourceforge.cruisecontrol.sourcecontrols.SVN&amp;quot;&lt;/span&gt; &lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now we want to build the project whenever there was a change to any of the Subversion repositories testing every 60 seconds.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;5
6
7
8
9
10
11
12
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;xml&quot;&gt;// in /path/to/cruisecontrol/config.xml
...
    &lt;span&gt;&lt;span&gt;&amp;lt;modificationset&lt;/span&gt; &lt;span&gt;quietperiod&lt;/span&gt;=&lt;span&gt;&amp;quot;60&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;svn&lt;/span&gt; &lt;span&gt;localWorkingCopy&lt;/span&gt;=&lt;span&gt;&amp;quot;projects/${project.name}/source/symfony/&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;svn&lt;/span&gt; &lt;span&gt;localWorkingCopy&lt;/span&gt;=&lt;span&gt;&amp;quot;projects/${project.name}/source/sfImageTransformPlugin/&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;svn&lt;/span&gt; &lt;span&gt;localWorkingCopy&lt;/span&gt;=&lt;span&gt;&amp;quot;projects/${project.name}/source/sfImageTransformExtraPlugin/&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;/modificationset&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
...&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The following tells CruiseControl what to do (running the build.xml through ant).&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;10
11
12
13
14
15
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;xml&quot;&gt;// in /path/to/cruisecontrol/config.xml
...
    &lt;span&gt;&lt;span&gt;&amp;lt;schedule&lt;/span&gt; &lt;span&gt;interval&lt;/span&gt;=&lt;span&gt;&amp;quot;300&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;ant&lt;/span&gt; &lt;span&gt;anthome&lt;/span&gt;=&lt;span&gt;&amp;quot;apache-ant-1.7.0&amp;quot;&lt;/span&gt; &lt;span&gt;buildfile&lt;/span&gt;=&lt;span&gt;&amp;quot;projects/${project.name}/build.xml&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;/schedule&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
...&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The following listener adds the build status to the dashboard.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;13
14
15
16
17
18
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;xml&quot;&gt;// in /path/to/cruisecontrol/config.xml
...
  &lt;span&gt;&lt;span&gt;&amp;lt;listeners&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;currentbuildstatuslistener&lt;/span&gt; &lt;span&gt;file&lt;/span&gt;=&lt;span&gt;&amp;quot;logs/${project.name}/status.txt&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;/listeners&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
...&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now let&amp;#8217;s tell CruiseControl where to find the logs and reports.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;16
17
18
19
20
21
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;xml&quot;&gt;// in /path/to/cruisecontrol/config.xml
...
  &lt;span&gt;&lt;span&gt;&amp;lt;log&lt;/span&gt; &lt;span&gt;dir&lt;/span&gt;=&lt;span&gt;&amp;quot;logs/${project.name}&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;merge&lt;/span&gt; &lt;span&gt;dir&lt;/span&gt;=&lt;span&gt;&amp;quot;projects/${project.name}/build/logs/&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;/log&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
...&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now publish the coverage report and some build metrics produced by phpuc.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;19
20
21
22
23
24
25
26
27
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;xml&quot;&gt;// in /path/to/cruisecontrol/config.xml
...
    &lt;span&gt;&lt;span&gt;&amp;lt;publishers&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;artifactspublisher&lt;/span&gt; &lt;span&gt;dir&lt;/span&gt;=&lt;span&gt;&amp;quot;projects/${project.name}/build/coverage&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;                          &lt;span&gt;dest&lt;/span&gt;=&lt;span&gt;&amp;quot;artifacts/${project.name}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;                          &lt;span&gt;subdirectory&lt;/span&gt;=&lt;span&gt;&amp;quot;coverage&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
       &lt;span&gt;&lt;span&gt;&amp;lt;execute&lt;/span&gt; &lt;span&gt;command&lt;/span&gt;=&lt;span&gt;&amp;quot;phpuc graph logs/${project.name} artifacts/${project.name}&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
     &lt;span&gt;&lt;span&gt;&amp;lt;/publishers&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
...&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now you can fire up CruiseControl and look at your project.&lt;/p&gt;
&lt;p&gt;Of course now you can start thinking about integrating PHP documentor, pdepend, PHP_Codesniffer and the lot. &lt;img src=&quot;http://test.ical.ly/wp-includes/images/smilies/icon_wink.gif&quot; alt=&quot;;)&quot; class=&quot;wp-smiley&quot; /&gt; &lt;/p&gt;
&lt;p&gt;Next steps for me will be to write the same post again for Hudson-CI and then compare the two.&lt;/p&gt;
&lt;h2&gt;The final files&lt;/h2&gt;
&lt;p&gt;Now here are the two XML files.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/path/to/cruisecontrol/projects/yourProjectName/build.xml&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;xml&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;lt;?xml&lt;/span&gt; &lt;span&gt;version&lt;/span&gt;=&lt;span&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt; &lt;span&gt;encoding&lt;/span&gt;=&lt;span&gt;&amp;quot;UTF-8&amp;quot;&lt;/span&gt;&lt;span&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;project&lt;/span&gt; &lt;span&gt;name&lt;/span&gt;=&lt;span&gt;&amp;quot;yourProjectName&amp;quot;&lt;/span&gt; &lt;span&gt;basedir&lt;/span&gt;=&lt;span&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;target&lt;/span&gt; &lt;span&gt;name&lt;/span&gt;=&lt;span&gt;&amp;quot;build&amp;quot;&lt;/span&gt; &lt;span&gt;depends&lt;/span&gt;=&lt;span&gt;&amp;quot;checkout,phpunit&amp;quot;&lt;/span&gt; &lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;target&lt;/span&gt; &lt;span&gt;name&lt;/span&gt;=&lt;span&gt;&amp;quot;checkout&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;exec&lt;/span&gt; &lt;span&gt;executable&lt;/span&gt;=&lt;span&gt;&amp;quot;svn&amp;quot;&lt;/span&gt; &lt;span&gt;dir&lt;/span&gt;=&lt;span&gt;&amp;quot;${basedir}/source/symfony&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;arg&lt;/span&gt; &lt;span&gt;line&lt;/span&gt;=&lt;span&gt;&amp;quot;up&amp;quot;&lt;/span&gt; &lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;/exec&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;exec&lt;/span&gt; &lt;span&gt;executable&lt;/span&gt;=&lt;span&gt;&amp;quot;svn&amp;quot;&lt;/span&gt; &lt;span&gt;dir&lt;/span&gt;=&lt;span&gt;&amp;quot;${basedir}/source/sfImageTransformPlugin&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;arg&lt;/span&gt; &lt;span&gt;line&lt;/span&gt;=&lt;span&gt;&amp;quot;up&amp;quot;&lt;/span&gt; &lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;/exec&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;exec&lt;/span&gt; &lt;span&gt;executable&lt;/span&gt;=&lt;span&gt;&amp;quot;svn&amp;quot;&lt;/span&gt; &lt;span&gt;dir&lt;/span&gt;=&lt;span&gt;&amp;quot;${basedir}/source/sfImageTransformExtraPlugin&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;arg&lt;/span&gt; &lt;span&gt;line&lt;/span&gt;=&lt;span&gt;&amp;quot;up&amp;quot;&lt;/span&gt; &lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;/exec&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;/target&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;target&lt;/span&gt; &lt;span&gt;name&lt;/span&gt;=&lt;span&gt;&amp;quot;phpunit&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;exec&lt;/span&gt; &lt;span&gt;executable&lt;/span&gt;=&lt;span&gt;&amp;quot;phpunit&amp;quot;&lt;/span&gt; &lt;span&gt;dir&lt;/span&gt;=&lt;span&gt;&amp;quot;${basedir}/source/sfImageTransformExtraPlugin&amp;quot;&lt;/span&gt; &lt;span&gt;failonerror&lt;/span&gt;=&lt;span&gt;&amp;quot;on&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;env&lt;/span&gt; &lt;span&gt;key&lt;/span&gt;=&lt;span&gt;&amp;quot;SYMFONY&amp;quot;&lt;/span&gt; &lt;span&gt;value&lt;/span&gt;=&lt;span&gt;&amp;quot;${basedir}/source/symfony/lib&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;arg&lt;/span&gt; &lt;span&gt;line&lt;/span&gt;=&lt;span&gt;&amp;quot;--log-xml ${basedir}/build/logs/phpunit.xml&lt;/span&gt;
&lt;span&gt;                 --log-pmd ${basedir}/build/logs/phpunit.pmd.xml&lt;/span&gt;
&lt;span&gt;                 --log-metrics ${basedir}/build/logs/phpunit.metrics.xml&lt;/span&gt;
&lt;span&gt;                 --coverage-clover ${basedir}/build/logs/phpunit.coverage.xml&lt;/span&gt;
&lt;span&gt;                 --coverage-html ${basedir}/build/coverage&lt;/span&gt;
&lt;span&gt;                 sfImageTransformExtraPluginTests&lt;/span&gt;
&lt;span&gt;                 test/sfImageTransformExtraPluginTests.php&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;/exec&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;/target&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/project&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;/path/to/cruisecontrol/config.xml&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre class=&quot;xml&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;lt;?xml&lt;/span&gt; &lt;span&gt;version&lt;/span&gt;=&lt;span&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt; &lt;span&gt;encoding&lt;/span&gt;=&lt;span&gt;&amp;quot;UTF-8&amp;quot;&lt;/span&gt;&lt;span&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;cruisecontrol&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;plugin&lt;/span&gt; &lt;span&gt;name&lt;/span&gt;=&lt;span&gt;&amp;quot;svn&amp;quot;&lt;/span&gt; &lt;span&gt;classname&lt;/span&gt;=&lt;span&gt;&amp;quot;net.sourceforge.cruisecontrol.sourcecontrols.SVN&amp;quot;&lt;/span&gt; &lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;project&lt;/span&gt; &lt;span&gt;name&lt;/span&gt;=&lt;span&gt;&amp;quot;yourProjectName&amp;quot;&lt;/span&gt; &lt;span&gt;buildafterfailed&lt;/span&gt;=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;modificationset&lt;/span&gt; &lt;span&gt;quietperiod&lt;/span&gt;=&lt;span&gt;&amp;quot;60&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;svn&lt;/span&gt; &lt;span&gt;localWorkingCopy&lt;/span&gt;=&lt;span&gt;&amp;quot;projects/${project.name}/source/symfony/&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;svn&lt;/span&gt; &lt;span&gt;localWorkingCopy&lt;/span&gt;=&lt;span&gt;&amp;quot;projects/${project.name}/source/sfImageTransformPlugin/&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;svn&lt;/span&gt; &lt;span&gt;localWorkingCopy&lt;/span&gt;=&lt;span&gt;&amp;quot;projects/${project.name}/source/sfImageTransformExtraPlugin/&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;/modificationset&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;schedule&lt;/span&gt; &lt;span&gt;interval&lt;/span&gt;=&lt;span&gt;&amp;quot;300&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;ant&lt;/span&gt; &lt;span&gt;anthome&lt;/span&gt;=&lt;span&gt;&amp;quot;apache-ant-1.7.0&amp;quot;&lt;/span&gt; &lt;span&gt;buildfile&lt;/span&gt;=&lt;span&gt;&amp;quot;projects/${project.name}/build.xml&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;/schedule&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;listeners&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;currentbuildstatuslistener&lt;/span&gt; &lt;span&gt;file&lt;/span&gt;=&lt;span&gt;&amp;quot;logs/${project.name}/status.txt&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;/listeners&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;log&lt;/span&gt; &lt;span&gt;dir&lt;/span&gt;=&lt;span&gt;&amp;quot;logs/${project.name}&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;merge&lt;/span&gt; &lt;span&gt;dir&lt;/span&gt;=&lt;span&gt;&amp;quot;projects/${project.name}/build/logs/&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;/log&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;publishers&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;span&gt;&amp;lt;artifactspublisher&lt;/span&gt; &lt;span&gt;dir&lt;/span&gt;=&lt;span&gt;&amp;quot;projects/${project.name}/build/coverage&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;                          &lt;span&gt;dest&lt;/span&gt;=&lt;span&gt;&amp;quot;artifacts/${project.name}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;                          &lt;span&gt;subdirectory&lt;/span&gt;=&lt;span&gt;&amp;quot;coverage&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
       &lt;span&gt;&lt;span&gt;&amp;lt;execute&lt;/span&gt; &lt;span&gt;command&lt;/span&gt;=&lt;span&gt;&amp;quot;phpuc graph logs/${project.name} artifacts/${project.name}&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
     &lt;span&gt;&lt;span&gt;&amp;lt;/publishers&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;/project&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/cruisecontrol&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;



&lt;!-- Begin SexyBookmarks Menu Code --&gt;
&lt;div class=&quot;sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-german&quot;&gt;
&lt;ul class=&quot;socials&quot;&gt;
		&lt;li class=&quot;sexy-twitter&quot;&gt;
			&lt;a href=&quot;http://twitter.com/home?status=Running+PHPUnit+tests+for+your+symfony+plugin+in+phpUnderControl+-+http://bit.ly/cdrIyp+(via+@testically)&amp;source=shareaholic&quot; rel=&quot;nofollow&quot; title=&quot;Twittere diesen Artikel!&quot;&gt;Twittere diesen Artikel!&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-delicious&quot;&gt;
			&lt;a href=&quot;http://delicious.com/post?url=http://test.ical.ly/2010/05/03/running-phpunit-tests-for-your-symfony-plugin-in-phpundercontrol/&amp;title=Running+PHPUnit+tests+for+your+symfony+plugin+in+phpUnderControl&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei del.icio.us&quot;&gt;Empfehle diesen Artikel bei del.icio.us&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-reddit&quot;&gt;
			&lt;a href=&quot;http://reddit.com/submit?url=http://test.ical.ly/2010/05/03/running-phpunit-tests-for-your-symfony-plugin-in-phpundercontrol/&amp;title=Running+PHPUnit+tests+for+your+symfony+plugin+in+phpUnderControl&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Reddit&quot;&gt;Empfehle diesen Artikel bei Reddit&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-stumbleupon&quot;&gt;
			&lt;a href=&quot;http://www.stumbleupon.com/submit?url=http://test.ical.ly/2010/05/03/running-phpunit-tests-for-your-symfony-plugin-in-phpundercontrol/&amp;title=Running+PHPUnit+tests+for+your+symfony+plugin+in+phpUnderControl&quot; rel=&quot;nofollow&quot; title=&quot;Bei StumbleUpon einstellen&quot;&gt;Bei StumbleUpon einstellen&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-linkedin&quot;&gt;
			&lt;a href=&quot;http://www.linkedin.com/shareArticle?mini=true&amp;url=http://test.ical.ly/2010/05/03/running-phpunit-tests-for-your-symfony-plugin-in-phpundercontrol/&amp;title=Running+PHPUnit+tests+for+your+symfony+plugin+in+phpUnderControl&amp;summary=As%20I%27ve%20just%20started%20to%20look%20into%20phpUnderControl%20again%20I%20thought%20why%20not%20try%20to%20setup%20a%20project%20for%20testing%20sfImageTransformExtraPlugin%20running%20all%20the%20PHPUnit%20tests%20that%20I%20wrote%20about%20last%20week.%0D%0A%0D%0ASo%20the%20goal%20is%20to%20setup%20a%20phpuc%20project%20for%20a%20single%20plugin%20but%20with%20all%20dependencies%20%28symfony%20itsel&amp;source=test.ical.ly&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei LinkedIn&quot;&gt;Empfehle diesen Artikel bei LinkedIn&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-technorati&quot;&gt;
			&lt;a href=&quot;http://technorati.com/faves?add=http://test.ical.ly/2010/05/03/running-phpunit-tests-for-your-symfony-plugin-in-phpundercontrol/&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Technorati&quot;&gt;Empfehle diesen Artikel bei Technorati&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-facebook&quot;&gt;
			&lt;a href=&quot;http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://test.ical.ly/2010/05/03/running-phpunit-tests-for-your-symfony-plugin-in-phpundercontrol/&amp;t=Running+PHPUnit+tests+for+your+symfony+plugin+in+phpUnderControl&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Facebook&quot;&gt;Empfehle diesen Artikel bei Facebook&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-google&quot;&gt;
			&lt;a href=&quot;http://test.ical.ly/2010/05/03/running-phpunit-tests-for-your-symfony-plugin-in-phpundercontrol/&quot; rel=&quot;nofollow&quot; title=&quot;&quot;&gt;&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-misterwong&quot;&gt;
			&lt;a href=&quot;http://www.mister-wong.de/addurl/?bm_url=http://test.ical.ly/2010/05/03/running-phpunit-tests-for-your-symfony-plugin-in-phpundercontrol/&amp;bm_description=Running+PHPUnit+tests+for+your+symfony+plugin+in+phpUnderControl&amp;plugin=sexybookmarks&quot; rel=&quot;nofollow&quot; title=&quot;F&#252;ge hinzu zu Mister Wong&quot;&gt;F&#252;ge hinzu zu Mister Wong&lt;/a&gt;
		&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;!-- End SexyBookmarks Menu Code --&gt;</content>
		<author>
			<name>Christian</name>
			<uri>http://test.ical.ly</uri>
		</author>
		<source>
			<title type="html">test.ical.ly &#187; phpUnit</title>
			<subtitle type="html">getting PHP by the balls</subtitle>
			<link rel="self" href="http://test.ical.ly/tags/phpunit/feed/atom/"/>
			<id>http://test.ical.ly/feed/atom/</id>
			<updated>2010-09-01T00:00:27+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Almost Done</title>
		<link href="http://qualityassuranceinphpprojects.com/archives/17-Almost-Done.html"/>
		<id>http://qualityassuranceinphpprojects.com/archives/17-guid.html</id>
		<updated>2010-04-30T11:30:00+00:00</updated>
		<content type="html">&lt;a href=&quot;http://www.flickr.com/photos/sebastian_bergmann/4564742479/&quot; title=&quot;Lucid Lynx by Sebastian Bergmann, on Flickr&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4029/4564742479_4b49b68ca2_m.jpg&quot; width=&quot;240&quot; height=&quot;140&quot; alt=&quot;Lucid Lynx&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
We are almost done with the manuscript for the &lt;a href=&quot;http://qualityassuranceinphpprojects.com/pages/german_edition.html&quot;&gt;German edition&lt;/a&gt; (&lt;a href=&quot;http://www.amazon.de/gp/product/3446419233?ie=UTF8&amp;tag=sbergmann&amp;linkCode=as2&amp;camp=1638&amp;creative=6742&amp;creativeASIN=3446419233&quot;&gt;preorder at Amazon.de&lt;/a&gt;) of the book. In a couple of days we can focus on getting the manuscript for the &lt;a href=&quot;http://qualityassuranceinphpprojects.com/pages/english_edition.html&quot;&gt;English edition&lt;/a&gt; (&lt;a href=&quot;http://www.amazon.com/Real-World-Developing-High-Quality-Frameworks-Applications/dp/0470872497/&quot;&gt;preorder at Amazon.com&lt;/a&gt;) ready for the publisher.</content>
		<author>
			<name>Sebastian Bergmann</name>
			<email>nospam@example.com</email>
			<uri>http://qualityassuranceinphpprojects.com/</uri>
		</author>
		<source>
			<title type="html">Quality Assurance in PHP Projects</title>
			<link rel="self" href="http://qualityassuranceinphpprojects.com/feeds/index.rss2"/>
			<id>http://qualityassuranceinphpprojects.com/feeds/index.rss2</id>
			<updated>2010-05-03T12:00:03+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Goodbye Cologne</title>
		<link href="http://www.manuel-pichler.de/archives/86-Goodbye-Cologne.html"/>
		<id>http://www.manuel-pichler.de/archives/86-guid.html</id>
		<updated>2010-04-29T11:20:00+00:00</updated>
		<content type="html">&lt;p&gt;As many of you may already have noticed, there will be a big change in my
career as a professional software engineer and architect this summer. Together
with &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2346&amp;entry_id=86&quot; title=&quot;http://kore-nordmann.de/blog/0095_ez_components_new_ways.txt&quot;&gt;Kore&lt;/a&gt; and &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2347&amp;entry_id=86&quot; title=&quot;http://schlitt.info/opensource/blog/0725_goodbye_ez_systems_hello_world.html&quot;&gt;Toby&lt;/a&gt; I am in the process of founding a company. The focus
of this company will be on services all around the whole quality life cycle in
PHP projects.&lt;/p&gt;

&lt;p&gt;Under the hood of our company we will also offer support, trainings and
consulting for several quality assurance tools, like &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2348&amp;entry_id=86&quot; title=&quot;http://pdepend.org&quot;&gt;pdepend&lt;/a&gt;, &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2349&amp;entry_id=86&quot; title=&quot;http://phpmd.org&quot;&gt;phpmd&lt;/a&gt; and
&lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2350&amp;entry_id=86&quot; title=&quot;http://phpundercontrol.org&quot;&gt;phpUnderControl&lt;/a&gt;. For you, this opens a great opportunity. You can use the
tools and the documentation, as well as participate in the community, as
usual. But from now on you can also purchase professional support, if you get
stuck or need general assitance.  And when you miss a feature or need an
individual extension for one of these tools, don't hesitate to contact us.&lt;/p&gt;

&lt;p&gt;I am really excited what cool things will happen in the next couple of years
and I am looking forward to cowork with professionals like &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2351&amp;entry_id=86&quot; title=&quot;http://schlitt.info/opensource/&quot;&gt;Toby&lt;/a&gt; and
&lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2352&amp;entry_id=86&quot; title=&quot;http://kore-nordmann.de&quot;&gt;Kore&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To finalize the little marketing for the company and its services &lt;img src=&quot;http://www.manuel-pichler.de/templates/default/img/emoticons/smile.png&quot; alt=&quot;:-)&quot; class=&quot;emoticon&quot; /&gt; I would
appreciate to meet you, your colleagues and your compmany, to give
presentations or into-depth trainings on one of the tools or on quality
assurance in general.&lt;/p&gt;</content>
		<author>
			<name>Manuel Pichler</name>
			<email>nospam@example.com</email>
			<uri>http://www.manuel-pichler.de/</uri>
		</author>
		<source>
			<title type="html">Manuel Pichler - phpundercontrol</title>
			<subtitle type="html">Trust is good, (phpUnder)Control is better.</subtitle>
			<link rel="self" href="http://manuel-pichler.de/feeds/categories/10-phpundercontrol.rss"/>
			<id>http://manuel-pichler.de/feeds/categories/10-phpundercontrol.rss</id>
			<updated>2010-06-10T11:00:28+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Noch mehr Erfahrungen mit PHPUnit Testing von symfony Plugins</title>
		<link href="http://test.ical.ly/2010/03/09/noch-mehr-erfahrungen-mit-phpunit-testing-von-symfony-plugins/"/>
		<id>http://test.ical.ly/?p=479</id>
		<updated>2010-04-26T08:28:53+00:00</updated>
		<content type="html">&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/03/unit-test-101_b16b3de3-b37c-41df-b1a9-b9675fb9019e.jpg&quot;&gt;&lt;img class=&quot;size-full wp-image-511 alignleft&quot; title=&quot;unit-test-101_b16b3de3-b37c-41df-b1a9-b9675fb9019e&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/03/unit-test-101_b16b3de3-b37c-41df-b1a9-b9675fb9019e.jpg&quot; alt=&quot;Unit Tests&quot; width=&quot;240&quot; height=&quot;180&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;This and some other posts have been summarised in the article &lt;a href=&quot;http://test.ical.ly/2010/04/26/best-practice-of-phpunit-testing-a-symfony-1-4-plugin/&quot;&gt;Best practice of PHPUnit testing a symfony 1.4 plugin&lt;/a&gt; (in English).&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Gestern sprach ich noch von Erkenntnissen. Heute muss ich eines davon bereits revidieren.&lt;/p&gt;
&lt;p&gt;Mehr noch, ich habe bisher zwei Stellen entdeckt, die einem den Spass Am Testen so richtig verderben k&#246;nnen: &lt;em&gt;sfContext &lt;/em&gt;und so ziemlich jede Form von Konfigurations Klasse.&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-479&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Also als erstes mal eine Richtigstellung.&lt;/p&gt;
&lt;h2&gt;Es ist keineswegs eine gute Idee die &lt;em&gt;ProjectConfiguration&lt;/em&gt; Klasse aus dem Fixture Projekt in &lt;em&gt;myPluginNameProjectConfiguration&lt;/em&gt; umzubenennen!&lt;/h2&gt;
&lt;p&gt;An irgendeiner Stelle ben&#246;tigt man sicher auch mal eine &lt;em&gt;sfApplicationConfiguration&lt;/em&gt; Instanz um bestimmte Settings zu laden.&lt;/p&gt;
&lt;p&gt;Diese Klasse aber wiederum erbt von der Klasse &lt;em&gt;ProjectConfiguration&lt;/em&gt;. Haben wir nun diese Klasse umbenannt wie ich gestern vorgeschlagen habe, wird sie nicht mehr gefunden und wir bekommen einen PHP Error.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Wir bleiben also vorerst mit dem Problem zur&#252;ck, dass TestSuites aus mehreren Plugins nicht in einer TestSuite zusdammen gefasst werden k&#246;nnen, weil es dadurch zur Redeklaration von Klassen kommen kann (wird).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;sfContext und symfony Konfigurations Klassen sind die Pest beim Testen!&lt;/h2&gt;
&lt;p&gt;Ernsthaft, das macht keinen Spass.&lt;/p&gt;
&lt;p&gt;Ich wollte u.a. meine PluginConfiguration Klasse testen, da ich dort einige statische Callbacks implementiert habe, die z.B. auf routing.load_configuration Event reagieren.&lt;/p&gt;
&lt;p&gt;Also Test Klasse anlegen und die &#246;ffentlichen Methoden (auch die statischen) mit jeweils einer Test Methode repr&#228;sentieren.&lt;/p&gt;
&lt;p&gt;Nun kommt man immer wieder in die Situation, wo man die komplette Konfiguration laden muss oder schlimmer: sfContext instanzieren, um an bestimmte Objekte wie sfEventDispatcher oder sfViewCacheManager zu kommen. Und alles nur um einzelne Metthoden zu testen, die irgendwo eine kleine Abh&#228;ngigkeit haben, die wiederum in einer Abh&#228;ngigkeitskaskade in sfContext m&#252;ndet.&lt;/p&gt;
&lt;p&gt;Im Ergebnis muss man immer einen kompletten Bootstrap durchf&#252;hren und das gesamte Framework &amp;#8220;hochfahren&amp;#8221;, um Unit Tests durchzuf&#252;hren.&lt;/p&gt;
&lt;p&gt;Einige meiner Tests dauern so bereits mehr als 30 Sekunden in der Ausf&#252;hrung. Das geht gar nicht!&lt;/p&gt;
&lt;p&gt;Ich werde mich also jetzt daran machen, so viel Anh&#228;ngigkeiten wie nur irgend m&#246;glich abzuschaffen. Aber ich f&#252;rchte, das wird mir nicht hundertprozentig gelingen.&lt;/p&gt;
&lt;p&gt;symfony 1 ist einfach dann doch so sehr&#160;verkoppelt, dass ich damit leben oder auf einige Tests verzichten muss.&lt;/p&gt;
&lt;p&gt;Mal schauen, ob ich da eine L&#246;sung finde..&lt;/p&gt;


&lt;!-- Begin SexyBookmarks Menu Code --&gt;
&lt;div class=&quot;sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-german&quot;&gt;
&lt;ul class=&quot;socials&quot;&gt;
		&lt;li class=&quot;sexy-twitter&quot;&gt;
			&lt;a href=&quot;http://twitter.com/home?status=Noch+mehr+Erfahrungen+mit+PHPUnit+Testing+von+symfony+Plugins+-+http://b2l.me/jgh7k+(via+@testically)&amp;source=shareaholic&quot; rel=&quot;nofollow&quot; title=&quot;Twittere diesen Artikel!&quot;&gt;Twittere diesen Artikel!&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-delicious&quot;&gt;
			&lt;a href=&quot;http://delicious.com/post?url=http://test.ical.ly/2010/03/09/noch-mehr-erfahrungen-mit-phpunit-testing-von-symfony-plugins/&amp;title=Noch+mehr+Erfahrungen+mit+PHPUnit+Testing+von+symfony+Plugins&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei del.icio.us&quot;&gt;Empfehle diesen Artikel bei del.icio.us&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-reddit&quot;&gt;
			&lt;a href=&quot;http://reddit.com/submit?url=http://test.ical.ly/2010/03/09/noch-mehr-erfahrungen-mit-phpunit-testing-von-symfony-plugins/&amp;title=Noch+mehr+Erfahrungen+mit+PHPUnit+Testing+von+symfony+Plugins&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Reddit&quot;&gt;Empfehle diesen Artikel bei Reddit&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-stumbleupon&quot;&gt;
			&lt;a href=&quot;http://www.stumbleupon.com/submit?url=http://test.ical.ly/2010/03/09/noch-mehr-erfahrungen-mit-phpunit-testing-von-symfony-plugins/&amp;title=Noch+mehr+Erfahrungen+mit+PHPUnit+Testing+von+symfony+Plugins&quot; rel=&quot;nofollow&quot; title=&quot;Bei StumbleUpon einstellen&quot;&gt;Bei StumbleUpon einstellen&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-linkedin&quot;&gt;
			&lt;a href=&quot;http://www.linkedin.com/shareArticle?mini=true&amp;url=http://test.ical.ly/2010/03/09/noch-mehr-erfahrungen-mit-phpunit-testing-von-symfony-plugins/&amp;title=Noch+mehr+Erfahrungen+mit+PHPUnit+Testing+von+symfony+Plugins&amp;summary=%0D%0A%0D%0AThis%20and%20some%20other%20posts%20have%20been%20summarised%20in%20the%20article%20Best%20practice%20of%20PHPUnit%20testing%20a%20symfony%201.4%20plugin%20%28in%20English%29.%0D%0A%0D%0AGestern%20sprach%20ich%20noch%20von%20Erkenntnissen.%20Heute%20muss%20ich%20eines%20davon%20bereits%20revidieren.%0D%0A%0D%0AMehr%20noch%2C%20ich%20habe%20bisher%20zwei%20Stellen%20entdeckt%2C%20die%20einem%20den%20Spass%20&amp;source=test.ical.ly&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei LinkedIn&quot;&gt;Empfehle diesen Artikel bei LinkedIn&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-technorati&quot;&gt;
			&lt;a href=&quot;http://technorati.com/faves?add=http://test.ical.ly/2010/03/09/noch-mehr-erfahrungen-mit-phpunit-testing-von-symfony-plugins/&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Technorati&quot;&gt;Empfehle diesen Artikel bei Technorati&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-facebook&quot;&gt;
			&lt;a href=&quot;http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://test.ical.ly/2010/03/09/noch-mehr-erfahrungen-mit-phpunit-testing-von-symfony-plugins/&amp;t=Noch+mehr+Erfahrungen+mit+PHPUnit+Testing+von+symfony+Plugins&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Facebook&quot;&gt;Empfehle diesen Artikel bei Facebook&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-google&quot;&gt;
			&lt;a href=&quot;http://test.ical.ly/2010/03/09/noch-mehr-erfahrungen-mit-phpunit-testing-von-symfony-plugins/&quot; rel=&quot;nofollow&quot; title=&quot;&quot;&gt;&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-misterwong&quot;&gt;
			&lt;a href=&quot;http://www.mister-wong.de/addurl/?bm_url=http://test.ical.ly/2010/03/09/noch-mehr-erfahrungen-mit-phpunit-testing-von-symfony-plugins/&amp;bm_description=Noch+mehr+Erfahrungen+mit+PHPUnit+Testing+von+symfony+Plugins&amp;plugin=sexybookmarks&quot; rel=&quot;nofollow&quot; title=&quot;F&#252;ge hinzu zu Mister Wong&quot;&gt;F&#252;ge hinzu zu Mister Wong&lt;/a&gt;
		&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;!-- End SexyBookmarks Menu Code --&gt;</content>
		<author>
			<name>Christian</name>
			<uri>http://test.ical.ly</uri>
		</author>
		<source>
			<title type="html">test.ical.ly &#187; phpUnit</title>
			<subtitle type="html">getting PHP by the balls</subtitle>
			<link rel="self" href="http://test.ical.ly/tags/phpunit/feed/atom/"/>
			<id>http://test.ical.ly/feed/atom/</id>
			<updated>2010-09-01T00:00:27+00:00</updated>
		</source>
	</entry>

	<entry>
		<title type="html">Der Weg zur Tanzfl&#228;che</title>
		<link href="http://priebsch.de/blog/der-weg-zur-tanzflaeche"/>
		<id>http://priebsch.de/blog/der-weg-zur-tanzflaeche</id>
		<updated>2010-04-15T11:41:49+00:00</updated>
		<content type="html">Es wurde schon viel dar&#252;ber spekuliert, wie gro&#223; der Anteil der PHP-Nutzer ist,
die von HipHop profitieren werden. Die Zahlen bewegen sich im Wesentlichen 
zwischen 0% und 100%, daher versuche ich mich gar nicht erst an einer eigenen
Sch&#228;tzung, sondern will stattdessen &#252;ber die Voraussetzungen schreiben, die
ein Team beziehungsweise eine Firma erf&#252;llen muss, um von HipHop profitieren zu
k&#246;nnen.</content>
		<author>
			<name>Stefan Priebsch</name>
			<email>stefan@priebsch.de</email>
			<uri>http://priebsch.de</uri>
		</author>
		<source>
			<title type="html">Stefan Priebsch</title>
			<subtitle type="html">Stefan Priebsch's Blog</subtitle>
			<link rel="self" href="http://priebsch.de/feeds/planetphpunit.xml"/>
			<id>http://priebsch.de/feeds/planetphpunit.xml</id>
			<updated>2010-06-18T23:00:24+00:00</updated>
		</source>
	</entry>

	<entry>
		<title type="html">Der erste deutsche PHP Summit</title>
		<link href="http://priebsch.de/blog/php-summit-in-duesseldorf"/>
		<id>http://priebsch.de/blog/php-summit-in-duesseldorf</id>
		<updated>2010-04-15T11:41:49+00:00</updated>
		<content type="html">Der erste deutsche PHP Summit - powered by thePHP.cc - ist eine neue und
einzigartige Veranstaltung, die alle wichtigen Themen rund um die
Software-Entwicklung mit PHP in kompakter Form vermittelt.</content>
		<author>
			<name>Stefan Priebsch</name>
			<email>stefan@priebsch.de</email>
			<uri>http://priebsch.de</uri>
		</author>
		<source>
			<title type="html">Stefan Priebsch</title>
			<subtitle type="html">Stefan Priebsch's Blog</subtitle>
			<link rel="self" href="http://priebsch.de/feeds/planetphpunit.xml"/>
			<id>http://priebsch.de/feeds/planetphpunit.xml</id>
			<updated>2010-06-18T23:00:24+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Using PHPUnit from a Git Checkout</title>
		<link href="http://sebastian-bergmann.de/archives/888-Using-PHPUnit-from-a-Git-Checkout.html"/>
		<id>http://sebastian-bergmann.de/archives/888-guid.html</id>
		<updated>2010-04-15T11:35:00+00:00</updated>
		<content type="html">&lt;p&gt;Users of PHPUnit frequently ask me questions such as &quot;&lt;em&gt;How do I use PHPUnit from a Git checkout?&lt;/em&gt;&quot; or &quot;&lt;em&gt;How do I run PHPUnit's own test suite?&lt;/em&gt;&quot; This article provides the answers to these questions.&lt;/p&gt;

&lt;h3&gt;Getting PHPUnit from Git&lt;/h3&gt;

&lt;dl&gt;&lt;dd&gt;&lt;small&gt;&lt;pre&gt;sb@thinkpad ~ % git clone git://github.com/sebastianbergmann/phpunit.git&lt;/pre&gt;&lt;/small&gt;&lt;/dd&gt;&lt;/dl&gt;

&lt;p&gt;You now have a &lt;code&gt;phpunit&lt;/code&gt; directory in your current working directory that contains the branch for PHPUnit 3.5 (at the time of writing) because the &lt;code&gt;3.5&lt;/code&gt; branch is currently configured as the &lt;em&gt;default&lt;/em&gt; branch for the PHPUnit repository on GitHub. If you want to switch to the branch for PHPUnit 3.4, for instance, you can use&lt;/p&gt;

&lt;dl&gt;&lt;dd&gt;&lt;small&gt;&lt;pre&gt;sb@thinkpad phpunit % git checkout -b 3.4 origin/3.4&lt;/pre&gt;&lt;/small&gt;&lt;/dd&gt;&lt;/dl&gt;

&lt;p&gt;This tells Git to create a new local branch of name &lt;code&gt;3.4&lt;/code&gt; (&lt;code&gt;-b 3.4&lt;/code&gt;) that is set up to track the remote branch &lt;code&gt;3.4&lt;/code&gt; from &lt;code&gt;origin&lt;/code&gt; (&lt;code&gt;origin/3.4&lt;/code&gt;). Git automatically switches to the newly created local branch. Using&lt;/p&gt;

&lt;dl&gt;&lt;dd&gt;&lt;small&gt;&lt;pre&gt;sb@thinkpad phpunit % git checkout 3.5&lt;/pre&gt;&lt;/small&gt;&lt;/dd&gt;&lt;/dl&gt;

&lt;p&gt;you can switch back to the branch for PHPUnit 3.5.&lt;/p&gt;

&lt;h3&gt;Running PHPUnit from a Git checkout&lt;/h3&gt;

&lt;p&gt;Inside the &lt;code&gt;phpunit&lt;/code&gt; directory you will find the &lt;code&gt;phpunit.php&lt;/code&gt; script. Using this script you can invoke the &lt;a href=&quot;http://www.phpunit.de/manual/current/en/textui.html&quot;&gt;PHPUnit TextUI test runner&lt;/a&gt;:&lt;/p&gt;

&lt;dl&gt;&lt;dd&gt;&lt;small&gt;&lt;pre&gt;sb@thinkpad ~ % phpunit/phpunit.php
PHPUnit @package_version@ by Sebastian Bergmann.
.
.
.&lt;/pre&gt;&lt;/small&gt;&lt;/dd&gt;&lt;/dl&gt;

&lt;p&gt;The &lt;code&gt;@package_version@&lt;/code&gt; placeholder string for the version information makes it clear that a non-release version of PHPUnit is being used. Upon installation, the PEAR Installer replaces this placeholder string with the relevant information.&lt;/p&gt;

&lt;h3&gt;Running PHPUnit's Own Test Suite&lt;/h3&gt;

&lt;p&gt;Running PHPUnit's own test suite is as easy as invoking &lt;code&gt;phpunit&lt;/code&gt; in the checkout directory:&lt;/p&gt;

&lt;dl&gt;&lt;dd&gt;&lt;small&gt;&lt;pre&gt;sb@thinkpad phpunit % phpunit                  
PHPUnit @package_version@ by Sebastian Bergmann.

............................................................  60 / 681
............................................................ 120 / 681
............................................................ 180 / 681
............................................................ 240 / 681
............................................................ 300 / 681
............................................................ 360 / 681
............................................................ 420 / 681
............................................................ 480 / 681
................................SSSSSSSSSSSSSSSSSSSSSSSSSSSS 540 / 681
SSSS.......................................S................ 600 / 681
............................................................ 660 / 681
.....................

Time: 27 seconds, Memory: 56.25Mb

OK, but incomplete or skipped tests!
Tests: 681, Assertions: 1459, Skipped: 33.

Writing code coverage data to XML file, this may take a moment.

Generating code coverage report, this may take a moment.&lt;/pre&gt;&lt;/small&gt;&lt;/dd&gt;&lt;/dl&gt;

&lt;p&gt;The above works because there is an XML configuration for PHPUnit (&lt;code&gt;phpunit.xml.dist&lt;/code&gt;) in the directory that contains information about which tests to run and what logfiles to produce.&lt;/p&gt;</content>
		<author>
			<name>Sebastian Bergmann</name>
			<email>nospam@example.com</email>
			<uri>http://sebastian-bergmann.de/</uri>
		</author>
		<source>
			<title type="html">Sebastian Bergmann - PHPUnit</title>
			<link rel="self" href="http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss"/>
			<id>http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss</id>
			<updated>2010-08-19T08:00:26+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Code Coverage Dashboard</title>
		<link href="http://sebastian-bergmann.de/archives/886-Code-Coverage-Dashboard.html"/>
		<id>http://sebastian-bergmann.de/archives/886-guid.html</id>
		<updated>2010-04-03T17:15:00+00:00</updated>
		<content type="html">&lt;p&gt;Almost &lt;a href=&quot;http://github.com/sebastianbergmann/php-code-coverage/commit/aa0aaabc6c8faeec350c558258f7460b491239b1&quot;&gt;a year ago&lt;/a&gt; I started to &lt;a href=&quot;http://en.wikipedia.org/wiki/Refactoring&quot;&gt;factor out&lt;/a&gt; all the code that deals with &lt;a href=&quot;http://en.wikipedia.org/wiki/Code_coverage&quot;&gt;code coverage&lt;/a&gt; in &lt;a href=&quot;http://www.phpunit.de/&quot;&gt;PHPUnit&lt;/a&gt; and put it into a separate component. The name of this component is &lt;a href=&quot;http://github.com/sebastianbergmann/php-code-coverage&quot;&gt;PHP_CodeCoverage&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;PHP_CodeCoverage is a library that provides collection, processing, and rendering functionality for PHP code coverage information. Its architecture has support for multiple backends for collecting code coverage information (currently only support for &lt;a href=&quot;http://xdebug.org/&quot;&gt;Xdebug&lt;/a&gt; is implemented) and for reporting code coverage information (for instance using Clover XML or as an HTML report).&lt;/p&gt;&lt;p&gt;As mentioned earlier, the HTML report that is generated by PHP_CodeCoverage shows the &lt;a href=&quot;http://sebastian-bergmann.de/archives/877-CRAP-in-PHPUnit-3.5.html&quot;&gt;CRAP Index&lt;/a&gt; software metric for each function or method. Today I built on this earlier development and added a &quot;dashboard view&quot; to the HTML report that shows the following software metrics:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Class Coverage Distribution&lt;/strong&gt;: This is a bar chart that shows how many classes have 0%, ..., 100% code coverage&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Class Complexity&lt;/strong&gt;: This is a scatter chart that shows the coverage (X axis) and the complexity (Y axis) of the classes&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Top Project Risks&lt;/strong&gt;: This is list of the classes with the highest &lt;a href=&quot;http://sebastian-bergmann.de/archives/877-CRAP-in-PHPUnit-3.5.html&quot;&gt;CRAP Index&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Least Tested Methods&lt;/strong&gt;: This is the list of the least tested methods&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;You can see an example of the dashboard view below:&lt;/p&gt;&lt;a href=&quot;http://www.flickr.com/photos/sebastian_bergmann/4486651271/&quot; title=&quot;PHP_CodeCoverage Dashboard View by Sebastian Bergmann, on Flickr&quot;&gt;&lt;img src=&quot;http://farm3.static.flickr.com/2780/4486651271_e3dd746234.jpg&quot; width=&quot;500&quot; height=&quot;267&quot; alt=&quot;PHP_CodeCoverage Dashboard View&quot; /&gt;&lt;/a&gt;</content>
		<author>
			<name>Sebastian Bergmann</name>
			<email>nospam@example.com</email>
			<uri>http://sebastian-bergmann.de/</uri>
		</author>
		<source>
			<title type="html">Sebastian Bergmann - PHPUnit</title>
			<link rel="self" href="http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss"/>
			<id>http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss</id>
			<updated>2010-08-19T08:00:26+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Testgetriebene Entwicklung (TDD) einer Funktion meines symfony Plugins</title>
		<link href="http://test.ical.ly/2010/03/31/testgetriebene-entwicklung-tdd-einer-funktion-meines-symfony-plugins/"/>
		<id>http://test.ical.ly/?p=607</id>
		<updated>2010-03-31T07:21:20+00:00</updated>
		<content type="html">&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/03/tdd_cycle.jpg&quot;&gt;&lt;img class=&quot;alignleft size-medium wp-image-609&quot; title=&quot;tdd_cycle&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/03/tdd_cycle-246x300.jpg&quot; alt=&quot;tdd_cycle&quot; width=&quot;246&quot; height=&quot;300&quot; /&gt;&lt;/a&gt;Wie ihr gemerkt habe, brauchte ich heute morgen etwas l&#228;nger f&#252;r meinen Blogpost. Der Grund ist, dass ich endlich eine L&#246;sung pr&#228;sentieren wollte f&#252;r &lt;a title=&quot;Was tun, wenn die Idee ausbleibt aber die Zeit knapp wird?&quot; href=&quot;http://test.ical.ly/2010/03/30/was-tun-wenn-die-idee-ausbleibt-aber-die-zeit-knapp-wird/&quot; target=&quot;_blank&quot;&gt;die Anforderung, f&#252;r die ich noch keine Idee hatte&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;R&#252;diger und Daniel haben mich korrekterweise darauf hingewiesen, dass keine L&#246;sung schlechter ist, als eine unelegante.&lt;/p&gt;
&lt;p&gt;Das wollte ich nicht auf mir sitzen lassen und habe nach einem Weg gesucht.&lt;/p&gt;
&lt;p&gt;Da ich die Anforderungen ziemlich genau benennen konnte, war ich auch in der Lage, sie als Unit Test zu formulieren und somit konnte ich Testgetrieben entwickeln (Test Driven Development, TDD).&lt;/p&gt;
&lt;p&gt;Witzigerweise bin ich mit dem Ergebnis sogar so zufrieden, dass ich es als (vorerst) elgante L&#246;sung bezeichnen w&#252;rde.&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-607&quot;&gt;&lt;/span&gt;Die Anforderung lautet wie folgt:&lt;/p&gt;
&lt;p&gt;Im sfImageTransformExtraPlugin hat der Anwender die M&#246;glichkeit, die URL Struktur seiner Thumbnails selber zu bestimmen.&#160;Unter diesen URLs werden die generierten Thumbnails im Docroot abgelegt.&#160;Das Entfernen der generierten Thumbnails soll eingrenzbar sein, indem Parameter der URL vorgegeben werden k&#246;nnen.&lt;/p&gt;
&lt;p&gt;Die Schwierigkeit ist, dass ich nicht weiss, welche Parameter es gibt, oder in welcher Reihenfolge sie kommen. Ich brauche also eine M&#246;glichkeit mir einen Pattern zu erstellen.&lt;/p&gt;
&lt;p&gt;Zun&#228;chst habe ich mir einige Fixtures erstellt.&lt;/p&gt;
&lt;pre&gt;thumbnails/default/path/to/file/filename.gif
thumbnails/default.gif
thumbnails/original/path/to/file/filename.jpg
thumbnails/original.jpg
thumbnails/site/default/path/to/file/filename.gif
thumbnails/site/original/path/to/file/filename.jpg
thumbnails/testrecord/default/01/00/00/test-record-1.gif
thumbnails/testrecord/default/02/00/00/test-record-2.gif
thumbnails/testrecord/original/01/00/00/test-record-1.jpg
thumbnails/testrecord/original/02/00/00/test-record-2.jpg
thumbnails/testrecord2/default/01/00/00/test-record-1.gif
thumbnails/testrecord2/default/02/00/00/test-record-2.gif
thumbnails/testrecord2/original/01/00/00/test-record-1.jpg
thumbnails/testrecord2/original/02/00/00/test-record-2.jpg&lt;/pre&gt;
&lt;p&gt;Mit diesen Fixtures kann ich feststellen, ob das gezielte Entfernen erfolgreich war oder nicht.&lt;/p&gt;
&lt;p&gt;Angefangen habe ich mit folgendem Test:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;php&quot;&gt;  &lt;span&gt;public&lt;/span&gt; &lt;span&gt;function&lt;/span&gt; testRemovePatternForFileSources&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
  &lt;span&gt;&amp;#123;&lt;/span&gt;
    &lt;span&gt;$pattern&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;computePattern&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'sf_image_mock'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;array&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'filepath'&lt;/span&gt; &lt;span&gt;=&amp;gt;&lt;/span&gt; &lt;span&gt;'path/to/file/filename'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$finder&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; sfFinder&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$files&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;$finder&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'file'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;getOption&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'cache_dir'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;removePattern&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$pattern&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertNotContains&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;getOption&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'cache_dir'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;'/thumbnails/default/path/to/file/filename.gif'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;$files&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertNotContains&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;getOption&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'cache_dir'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;'/thumbnails/original/path/to/file/filename.jpg'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;$files&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertEquals&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;count&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$files&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt; &lt;span&gt;-&lt;/span&gt; &lt;span&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;count&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$finder&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'file'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;getOption&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'cache_dir'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Die Idee ist also, irgendwie einen Pattern zu erstellen (Zeile 93) und mit diesem die symfony Methode &lt;em&gt;removePattern()&lt;/em&gt; aufzurufen.&lt;/p&gt;
&lt;p&gt;Im Nachgang sollten nur einige bestimmte Dateien entfernt sein und der Rest eben nicht. Ich &#252;berpr&#252;fe also, ob die beiden Dateien nicht mehr vorhanden sind und ob die gesamt Anzahl der noch vorhandenen Dateien nur um genau diese beiden verringert worden ist.&lt;/p&gt;
&lt;p&gt;Nach einigen Versuchen habe ich den Test gr&#252;n machen k&#246;nnen, war aber noch nicht hundertprozentig zufrieden. Der Pattern, den ich mir erstellt hatte war zu weich und konnte unter Umst&#228;nden zu viel matchen.&lt;/p&gt;
&lt;p&gt;Hierbei ist mir aufgefallen, dass das Pattern erstellen und &#252;berpr&#252;fen sehr eng nicht mit der &lt;em&gt;sfRawFileCache&lt;/em&gt; Klasse, sondern viel mehr mit der &lt;em&gt;sfImageTransformRoute&lt;/em&gt; Klasse zusammenh&#228;ngt, denn diese hat bereits einen Pattern, der entsprechende URLs matcht. Ich musste eigentlich nur daf&#252;r sorgen, dass dieser sehr flexible Pattern einschr&#228;nkbar ist und dann musste ich nur noch die symfony Methode &lt;em&gt;sfRoute::matchesUrl()&lt;/em&gt; aufrufen.&lt;/p&gt;
&lt;p&gt;Hier mal der entsprechende Test:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;php&quot;&gt;  &lt;span&gt;public&lt;/span&gt; &lt;span&gt;function&lt;/span&gt; testRemovePatternForFileSources&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
  &lt;span&gt;&amp;#123;&lt;/span&gt;
    &lt;span&gt;$route&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;getRoute&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'sf_image_file'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$route&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;preassemblePattern&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;array&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'filepath'&lt;/span&gt; &lt;span&gt;=&amp;gt;&lt;/span&gt; &lt;span&gt;'path/to/file/filename'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$finder&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; sfFinder&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$starting_count&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;count&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$finder&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'file'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;getOption&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'cache_dir'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;removePattern&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$route&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$files&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;$finder&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'file'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;getOption&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'cache_dir'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertNotContains&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;getOption&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'cache_dir'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;'/thumbnails/default/path/to/file/filename.gif'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;$files&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertNotContains&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;getOption&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'cache_dir'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;'/thumbnails/original/path/to/file/filename.jpg'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;$files&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;assertEquals&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$starting_count&lt;/span&gt; &lt;span&gt;-&lt;/span&gt; &lt;span&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;count&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$files&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
  &lt;span&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Statt also einen Pattern generieren zu lassen, hole ich mir eine Route und schr&#228;nke deren Pattern mit &lt;em&gt;preassemblePattern()&lt;/em&gt; um ein paar Parameter ein.&lt;/p&gt;
&lt;p&gt;Der &lt;em&gt;sfRawFileCache&lt;/em&gt; &#252;bergebe ich dann statt einem Pattern dieses Route Objekt.&lt;/p&gt;
&lt;p&gt;Hier die &#196;nderungen daf&#252;r:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;diff&quot;&gt;Index: /plugins/sfImageTransformExtraPlugin/trunk/lib/cache/sfRawFileCache.class.php
===================================================================
&lt;span&gt;--- /plugins/sfImageTransformExtraPlugin/trunk/lib/cache/sfRawFileCache.class.php &lt;span&gt;&amp;#40;&lt;/span&gt;revision &lt;span&gt;28779&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;+++ /plugins/sfImageTransformExtraPlugin/trunk/lib/cache/sfRawFileCache.class.php &lt;span&gt;&amp;#40;&lt;/span&gt;revision &lt;span&gt;28904&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;@@ -&lt;span&gt;99&lt;/span&gt;,&lt;span&gt;5&lt;/span&gt; +&lt;span&gt;99&lt;/span&gt;,&lt;span&gt;16&lt;/span&gt; @@&lt;/span&gt;
public function removePattern&lt;span&gt;&amp;#40;&lt;/span&gt;$pattern&lt;span&gt;&amp;#41;&lt;/span&gt;
&lt;span&gt;&amp;#123;&lt;/span&gt;
&lt;span&gt;-    if &lt;span&gt;&amp;#40;&lt;/span&gt;false !== strpos&lt;span&gt;&amp;#40;&lt;/span&gt;$pattern, '**'&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;+    if&lt;span&gt;&amp;#40;&lt;/span&gt;$pattern instanceof sfRoute&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;+    &lt;span&gt;&amp;#123;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;+      $paths = array&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;;&lt;/span&gt;
&lt;span&gt;+      foreach &lt;span&gt;&amp;#40;&lt;/span&gt;new RecursiveIteratorIterator&lt;span&gt;&amp;#40;&lt;/span&gt;new RecursiveDirectoryIterator&lt;span&gt;&amp;#40;&lt;/span&gt;$this-&amp;gt;getOption&lt;span&gt;&amp;#40;&lt;/span&gt;'cache_dir'&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt; as $path&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;+      &lt;span&gt;&amp;#123;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;+        if&lt;span&gt;&amp;#40;&lt;/span&gt;false !== $pattern-&amp;gt;matchesUrl&lt;span&gt;&amp;#40;&lt;/span&gt;'/'.str_replace&lt;span&gt;&amp;#40;&lt;/span&gt;$this-&amp;gt;getOption&lt;span&gt;&amp;#40;&lt;/span&gt;'cache_dir'&lt;span&gt;&amp;#41;&lt;/span&gt;.DIRECTORY_SEPARATOR, '', $path&lt;span&gt;&amp;#41;&lt;/span&gt;, array&lt;span&gt;&amp;#40;&lt;/span&gt;'method' =&amp;gt; 'get'&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;+        &lt;span&gt;&amp;#123;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;+          $paths&lt;span&gt;&amp;#91;&lt;/span&gt;&lt;span&gt;&amp;#93;&lt;/span&gt; = $path;&lt;/span&gt;
&lt;span&gt;+        &lt;span&gt;&amp;#125;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;+      &lt;span&gt;&amp;#125;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;+    &lt;span&gt;&amp;#125;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;+    else if &lt;span&gt;&amp;#40;&lt;/span&gt;false !== strpos&lt;span&gt;&amp;#40;&lt;/span&gt;$pattern, '**'&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&amp;#123;&lt;/span&gt;
$pattern = str_replace&lt;span&gt;&amp;#40;&lt;/span&gt;sfCache::SEPARATOR, DIRECTORY_SEPARATOR, $pattern&lt;span&gt;&amp;#41;&lt;/span&gt;;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;und&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;diff&quot;&gt;Index: /plugins/sfImageTransformExtraPlugin/trunk/lib/routing/sfImageTransformRoute.class.php
===================================================================
&lt;span&gt;--- /plugins/sfImageTransformExtraPlugin/trunk/lib/routing/sfImageTransformRoute.class.php &lt;span&gt;&amp;#40;&lt;/span&gt;revision &lt;span&gt;28653&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;+++ /plugins/sfImageTransformExtraPlugin/trunk/lib/routing/sfImageTransformRoute.class.php &lt;span&gt;&amp;#40;&lt;/span&gt;revision &lt;span&gt;28904&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;@@ -&lt;span&gt;146&lt;/span&gt;,&lt;span&gt;3&lt;/span&gt; +&lt;span&gt;146&lt;/span&gt;,&lt;span&gt;21&lt;/span&gt; @@&lt;/span&gt;
return call_user_func&lt;span&gt;&amp;#40;&lt;/span&gt;array&lt;span&gt;&amp;#40;&lt;/span&gt;$this-&amp;gt;getImageSourceStreamWrapper&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;, 'buildURIfromParameters'&lt;span&gt;&amp;#41;&lt;/span&gt;, $this-&amp;gt;parameters&lt;span&gt;&amp;#41;&lt;/span&gt;;
&lt;span&gt;&amp;#125;&lt;/span&gt;
&lt;span&gt;+&lt;/span&gt;
&lt;span&gt;+  /**&lt;/span&gt;
&lt;span&gt;+   * Preassembles pattern with passed parameters&lt;/span&gt;
&lt;span&gt;+   *&lt;/span&gt;
&lt;span&gt;+   * This is used to limit matches when removing generated images&lt;/span&gt;
&lt;span&gt;+   *&lt;/span&gt;
&lt;span&gt;+   * @param  array $params Parameters to be encoded in the pattern&lt;/span&gt;
&lt;span&gt;+   * @return void&lt;/span&gt;
&lt;span&gt;+   */&lt;/span&gt;
&lt;span&gt;+  public function preassemblePattern&lt;span&gt;&amp;#40;&lt;/span&gt;$params = array&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;+  &lt;span&gt;&amp;#123;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;+    foreach&lt;span&gt;&amp;#40;&lt;/span&gt;$params as $key =&amp;gt; $value&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;+    &lt;span&gt;&amp;#123;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;+      $this-&amp;gt;pattern = str_replace&lt;span&gt;&amp;#40;&lt;/span&gt;':'.$key, $value, $this-&amp;gt;pattern&lt;span&gt;&amp;#41;&lt;/span&gt;;&lt;/span&gt;
&lt;span&gt;+    &lt;span&gt;&amp;#125;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;+&lt;/span&gt;
&lt;span&gt;+    $this-&amp;gt;compiled = false;&lt;/span&gt;
&lt;span&gt;+  &lt;span&gt;&amp;#125;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So, der Test ist gr&#252;n, der Code ist eingecheckt und ich bin zufrieden! &lt;img src=&quot;http://test.ical.ly/wp-includes/images/smilies/icon_smile.gif&quot; alt=&quot;:)&quot; class=&quot;wp-smiley&quot; /&gt; &lt;/p&gt;
&lt;p&gt;Das ganze Changeset k&#246;nnt ihr hier sehen:&lt;br /&gt;
&lt;a href=&quot;http://trac.symfony-project.org/changeset/28904&quot; target=&quot;_blank&quot;&gt;http://trac.symfony-project.org/changeset/28904&lt;/a&gt;&lt;/p&gt;


&lt;!-- Begin SexyBookmarks Menu Code --&gt;
&lt;div class=&quot;sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-german&quot;&gt;
&lt;ul class=&quot;socials&quot;&gt;
		&lt;li class=&quot;sexy-twitter&quot;&gt;
			&lt;a href=&quot;http://twitter.com/home?status=Testgetriebene+Entwicklung+%28TDD%29+einer+Funktion+meines+symfony+Plugins+-+http://b2l.me/msbdd+(via+@testically)&amp;source=shareaholic&quot; rel=&quot;nofollow&quot; title=&quot;Twittere diesen Artikel!&quot;&gt;Twittere diesen Artikel!&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-delicious&quot;&gt;
			&lt;a href=&quot;http://delicious.com/post?url=http://test.ical.ly/2010/03/31/testgetriebene-entwicklung-tdd-einer-funktion-meines-symfony-plugins/&amp;title=Testgetriebene+Entwicklung+%28TDD%29+einer+Funktion+meines+symfony+Plugins&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei del.icio.us&quot;&gt;Empfehle diesen Artikel bei del.icio.us&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-reddit&quot;&gt;
			&lt;a href=&quot;http://reddit.com/submit?url=http://test.ical.ly/2010/03/31/testgetriebene-entwicklung-tdd-einer-funktion-meines-symfony-plugins/&amp;title=Testgetriebene+Entwicklung+%28TDD%29+einer+Funktion+meines+symfony+Plugins&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Reddit&quot;&gt;Empfehle diesen Artikel bei Reddit&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-stumbleupon&quot;&gt;
			&lt;a href=&quot;http://www.stumbleupon.com/submit?url=http://test.ical.ly/2010/03/31/testgetriebene-entwicklung-tdd-einer-funktion-meines-symfony-plugins/&amp;title=Testgetriebene+Entwicklung+%28TDD%29+einer+Funktion+meines+symfony+Plugins&quot; rel=&quot;nofollow&quot; title=&quot;Bei StumbleUpon einstellen&quot;&gt;Bei StumbleUpon einstellen&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-linkedin&quot;&gt;
			&lt;a href=&quot;http://www.linkedin.com/shareArticle?mini=true&amp;url=http://test.ical.ly/2010/03/31/testgetriebene-entwicklung-tdd-einer-funktion-meines-symfony-plugins/&amp;title=Testgetriebene+Entwicklung+%28TDD%29+einer+Funktion+meines+symfony+Plugins&amp;summary=Wie%20ihr%20gemerkt%20habe%2C%20brauchte%20ich%20heute%20morgen%20etwas%20l%C3%A4nger%20f%C3%BCr%20meinen%20Blogpost.%20Der%20Grund%20ist%2C%20dass%20ich%20endlich%20eine%20L%C3%B6sung%20pr%C3%A4sentieren%20wollte%20f%C3%BCr%20die%20Anforderung%2C%20f%C3%BCr%20die%20ich%20noch%20keine%20Idee%20hatte.%0D%0A%0D%0AR%C3%BCdiger%20und%20Daniel%20haben%20mich%20korrekterweise%20darauf%20hingewiesen%2C%20dass%20keine%20L%C3%B6sung%20schl&amp;source=test.ical.ly&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei LinkedIn&quot;&gt;Empfehle diesen Artikel bei LinkedIn&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-technorati&quot;&gt;
			&lt;a href=&quot;http://technorati.com/faves?add=http://test.ical.ly/2010/03/31/testgetriebene-entwicklung-tdd-einer-funktion-meines-symfony-plugins/&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Technorati&quot;&gt;Empfehle diesen Artikel bei Technorati&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-facebook&quot;&gt;
			&lt;a href=&quot;http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://test.ical.ly/2010/03/31/testgetriebene-entwicklung-tdd-einer-funktion-meines-symfony-plugins/&amp;t=Testgetriebene+Entwicklung+%28TDD%29+einer+Funktion+meines+symfony+Plugins&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Facebook&quot;&gt;Empfehle diesen Artikel bei Facebook&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-google&quot;&gt;
			&lt;a href=&quot;http://test.ical.ly/2010/03/31/testgetriebene-entwicklung-tdd-einer-funktion-meines-symfony-plugins/&quot; rel=&quot;nofollow&quot; title=&quot;&quot;&gt;&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-misterwong&quot;&gt;
			&lt;a href=&quot;http://www.mister-wong.de/addurl/?bm_url=http://test.ical.ly/2010/03/31/testgetriebene-entwicklung-tdd-einer-funktion-meines-symfony-plugins/&amp;bm_description=Testgetriebene+Entwicklung+%28TDD%29+einer+Funktion+meines+symfony+Plugins&amp;plugin=sexybookmarks&quot; rel=&quot;nofollow&quot; title=&quot;F&#252;ge hinzu zu Mister Wong&quot;&gt;F&#252;ge hinzu zu Mister Wong&lt;/a&gt;
		&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;!-- End SexyBookmarks Menu Code --&gt;</content>
		<author>
			<name>Christian</name>
			<uri>http://test.ical.ly</uri>
		</author>
		<source>
			<title type="html">test.ical.ly &#187; phpUnit</title>
			<subtitle type="html">getting PHP by the balls</subtitle>
			<link rel="self" href="http://test.ical.ly/tags/phpunit/feed/atom/"/>
			<id>http://test.ical.ly/feed/atom/</id>
			<updated>2010-09-01T00:00:27+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Mehr zu PHPUnit Tests in symfony Plugins</title>
		<link href="http://test.ical.ly/2010/03/11/mehr-zu-phpunit-tests-in-symfony-plugins/"/>
		<id>http://test.ical.ly/?p=513</id>
		<updated>2010-03-23T12:16:49+00:00</updated>
		<content type="html">&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/03/MockUp1.jpg&quot;&gt;&lt;img class=&quot;alignleft size-full wp-image-515&quot; title=&quot;MockUp&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/03/MockUp1.jpg&quot; alt=&quot;MockUp&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;Gestern hab ich mich etwas dar&#252;ber ausgelassen, wie doof doch einige Code Koppelungen von symfony mir das Testen behinderten.&lt;/p&gt;
&lt;p&gt;Vor allem drei Dinge haben mir das Leben schwer gemacht: die Konfiguration, sfContext und Datenbankabh&#228;ngigkeiten.&#160;Und ich habe f&#252;r alle drei auch Antworten finden k&#246;nnen. Vielleicht nicht die endg&#252;ltigen, aber schon sehr akzeptable, wie ich meine.&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-513&quot;&gt;&lt;/span&gt;Vielleicht sag ich erstmal, was &#252;berhaupt meine Probleme waren.&lt;/p&gt;
&lt;p&gt;Zum einen ist es nicht immer ganz leicht herauszufinden, was man nun alles initialisieren muss, um eine Klasse zu Testen. Und f&#252;r die Dinge, die initialisiert werden sollen, ist es nicht immer ganz einfach herauszufinden, was man dazu alles hochfahren und welche Konfiguration geladen werden muss.&lt;/p&gt;
&lt;p&gt;Das f&#252;hrte dazu, dass ein Test alleine durchlaufen konnte, aber es in einer Test Suite nicht mehr tat. Und wenn man ihn da zum Laufen bekommen hat, konnte er immer noch auf dem Continuous Integration Server fehlschlagen.&lt;/p&gt;
&lt;p&gt;Ein anderes Problem war die Ausf&#252;hrungszeit der Tests vor allem auf dem CI Server. Spitzenzeiten von bis zu 5 Minuten finde ich mehr als grenzwertig, wenn man sich mal den Umfang meines Projektes vergegenw&#228;rtigt (ca. 13 &#252;berschaubare Klassen inklusive der Controller).&lt;/p&gt;
&lt;p&gt;Unterm Strich waren meine Tests alle zusammen wenig stabil und zu langsam.&lt;/p&gt;
&lt;p&gt;Als Grund f&#252;r die lange Ausf&#252;hrungszeit konnte ich ganz klar den Bootstrap von symfony ausmachen. Das st&#228;ndige Hochfahren des Frameworks ging extrem auf die Performance.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/03/alltests21.jpg&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-518&quot; title=&quot;alltests2&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/03/alltests21.jpg&quot; alt=&quot;alltests2&quot; width=&quot;609&quot; height=&quot;291&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Bei dieser Testdauer &#220;bersicht kann man schon ahnen, wo die Probleme liegen. Hier mal die teuren vier:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;sfImageTransformExtraPluginConfigurationTest &lt;/em&gt;testet die Plugin Configuration, die bereits alle anderen Configs ben&#246;tigt, um &#252;berhaupt richtig instanziiert werden zu k&#246;nnen&lt;/li&gt;
&lt;li&gt;&lt;em&gt;sfImageSourceTemplateTest&lt;/em&gt; testet ein Doctrine Behaviour, welches ein Doctrine_Record ben&#246;tigt, um die einzelnen Methoden aufrufen zu k&#246;nnen&lt;/li&gt;
&lt;li&gt;&lt;em&gt;sfImageTransformManagerTest&lt;/em&gt; ist tats&#228;chlich nicht ganz sauber entworfen.. (Das habe ich aber &lt;a title=&quot;Mein erstes Test-getriebenes Refactoring&quot; href=&quot;http://test.ical.ly/2010/03/10/mein-erstes-test-getriebenes-refactoring/&quot; target=&quot;_parent&quot;&gt;gestern bereits korrigiert!&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;sfImageSourceDoctrineTest&lt;/em&gt; testet einen Stream Wrapper, der eine Resource zur&#252;ckliefert, die er mit Hilfe der Datenbank bestimmt&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Mittlerweile sieht die gleiche &#220;bersicht wie folgt aus:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/03/alltest_new.jpg&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-519&quot; title=&quot;alltest_new&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/03/alltest_new.jpg&quot; alt=&quot;alltest_new&quot; width=&quot;562&quot; height=&quot;279&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Das kann sich schon eher sehen lassen. Eine Ausf&#252;hrzeit von 6 Sekunden ist auf jeden Fall akzeptabel, was ja nicht nur f&#252;r den CI Server sondern vor allem f&#252;r die manuelle Ausf&#252;hrung w&#228;hrend der Entwicklung kritisch ist.&lt;/p&gt;
&lt;p&gt;Aber was habe ich gemacht?&lt;/p&gt;
&lt;h2&gt;Separation des Plugins&lt;/h2&gt;
&lt;p&gt;Unbedingt notwendig f&#252;r eine h&#246;here Stabilit&#228;t der Tests unter verschiedenen Umgebungen (Entwicklungsumgebung und Continuous Integration Server) war es das zu testende Plugin aus dem Projekt zu l&#246;sen. Das heisst:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Eine separate Entwicklungsumgebung&lt;/strong&gt;. Um zu vermeiden, dass man doch Projekt-Abh&#228;ngigkeiten einbaut und mittestet, sollte die Entwicklung des Plugins separat stattfinden oder zumindest das Testen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ein separater PHPUnit Aufruf&lt;/strong&gt;. Damit bekommt man auch Konflikte wie gleich benannte Klassen in den Griff. &#220;berhaupt besteht im Grunde genommen kein Grund in einem Projekt auch alle darin genutzten Plugins zu testen, denn diese sollen ja vor allem Projekt-unabh&#228;ngig funktionieren.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ein separater CI Job&lt;/strong&gt;. Zu finden unter&#160;&lt;a title=&quot;Hudson Job sfImageTransformExtraPlugin&quot; href=&quot;http://automat.ical.ly/job/sfImageTransformExtraPlugin/&quot; target=&quot;_blank&quot;&gt;http://automat.ical.ly/job/sfImageTransformExtraPlugin/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ein separates Repository&lt;/strong&gt;. Das macht es dem CI Server einfacher, einfach Subversion nach updates zu befragen, ohne dass Plugin und Projekt Updates sich gegenseitig ins Testing schiessen.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Als &amp;#8220;Entwicklungsumgebung&amp;#8221; reicht es mir aus, das Plugin irgendwo ohne symfony Projekt abzulegen und lediglich die symfony Bibliotheken bereitzustellen (&lt;em&gt;export SYMFONY=&amp;#8230;./symfony/lib&lt;/em&gt;).&#160;Sobald kein Projekt mehr vorhanden ist und die Tests trotzdem durchlaufen, kann man sicher sein, dass es keine Abh&#228;ngigkeiten gibt.&lt;/p&gt;
&lt;p&gt;Der separate PHPUnit Aufruf hat zwei Vorteile. Zum einen umgeht es den Namenskonflikt, &#252;ber den ich vorgestern gestolpert bin. Zum anderen werde ich solche Aufrufe nur noch direkt aus dem Plugin Basisverzeichnis ausf&#252;hren. Denn sobald ich eine phpunit.xml anlege, weiss ich, dass die darin enthaltenen Pfade relativ zum Plugin sind.&lt;/p&gt;
&lt;p&gt;Ein separater CI Job macht ebenfalls total Sinn, denn dann kann ich dort separat konfigurieren und bringe nicht&#160;eventuelle Projekt-Abh&#228;ngigkeiten in die Testumgebung.&lt;/p&gt;
&lt;p&gt;Das separate Repository ist erstmal optional, aber sicher sinnig, wenn ich dieses Plugin auch in anderen Projekten nutzen will.&lt;/p&gt;
&lt;h2&gt;Doctrine Verbindung mocken&lt;/h2&gt;
&lt;p&gt;Die Doctrine Datenbank Verbindung kostet Zeit und ist bisher aber gar nicht wirklich n&#246;tig, weil ich gar keine Modelle im Projekt habe, sondern lediglich mit Modellen aus dem Projekt zusammenarbeiten will.&lt;/p&gt;
&lt;p&gt;Eine DSN habe ich wie folgt angegeben, aber obwohl SQLite f&#252;r Testzwecke sicher besser ist, als MySQL o.&#228;. ist die Auswirkung auf die Performance recht gross.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;yaml&quot;&gt;all:
  doctrine:
    class: sfDoctrineDatabase
    param:
      dsn: sqlite:////fixture.db&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Deshalb habe ich in den &lt;em&gt;setUp()&lt;/em&gt; Methoden der TestCases, die irgendwie mit Doctrine arbeiten folgenden Schnipsel eingebaut:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;php&quot;&gt;    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;amp;&lt;/span&gt;gt&lt;span&gt;;&lt;/span&gt;dbh &lt;span&gt;=&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; Doctrine_Adapter_Mock&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'mysql'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;amp;&lt;/span&gt;gt&lt;span&gt;;&lt;/span&gt;conn &lt;span&gt;=&lt;/span&gt; Doctrine_Manager&lt;span&gt;::&lt;/span&gt;&lt;span&gt;getInstance&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;-&amp;amp;&lt;/span&gt;gt&lt;span&gt;;&lt;/span&gt;openConnection&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;amp;&lt;/span&gt;gt&lt;span&gt;;&lt;/span&gt;dbh&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'mysql'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;true&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Das &lt;em&gt;true&lt;/em&gt; ist wichig, denn es aktiviert auch gleich die so &#252;bergebene Verbindung.&lt;/p&gt;
&lt;p&gt;Im Ergebnis wird die &lt;em&gt;fixtures.db&lt;/em&gt; gar nicht mehr angelegt. Die DSN wird lediglich zum initialisieren ben&#246;tigt, Doctrine danach aber wieder umkonfiguriert.&lt;/p&gt;
&lt;p&gt;Im Sourcecode von Doctrine habe ich auch entdeckt, dass man eine DSN mit dem &lt;em&gt;mock://&lt;/em&gt; Protokoll angeben kann, aber das habe ich noch nicht zum Laufen bekommen. Sollte ich das noch hinbekommen, k&#246;nnte ich mir aber sogar den Schnipsel sparen.&lt;/p&gt;
&lt;h2&gt;Ein Doctrine_Record mocken&lt;/h2&gt;
&lt;p&gt;Wenn ich keine eigenen Modelle habe und mich auch nicht Daten aus irgendeiner Datenbank bedienen m&#246;chte (und darf!), dann brauche ich ein Mock-Doctrine_Record und eine dazugeh&#246;rige Mock-Doctrine_Table.&lt;/p&gt;
&lt;p&gt;Das require() ich einfach &#252;berall, wo ich sowas ben&#246;tige und implementiere dort alles, was ich von diesem Record in Tests ben&#246;tige. Ich muss allerdings aufpassen, nichts Test-kritisches zu mocken, was eventuell zu einem allways-pass f&#252;hrt. Nur Sachen mocken, um Abh&#228;ngigkeiten aufzul&#246;sen!&lt;/p&gt;
&lt;h2&gt;sfContext nicht &#246;fter instanziieren als notwendig&lt;/h2&gt;
&lt;p&gt;Ich habe gelernt, dass die setUp() Methode in einem TestCase mit dessen Instanziierung ausgef&#252;hrt wird. Damit hatte ich angenommen, dass sie einmal vor allen im TestCase enthaltenen Test-Methoden l&#228;uft. Das stimmt aber so nicht.&lt;/p&gt;
&lt;p&gt;Ein TestCase wird f&#252;r jede in ihm enthaltene Test Methode erneut instanziiert!&lt;/p&gt;
&lt;p&gt;Wenn ich dann in der setUp() Methode ein sfContext Objekt erzeuge, dann mache ich das erneut pro Test Methode. Doof.&lt;/p&gt;
&lt;p&gt;Folgender Schnipsel hilft da gewaltig:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;php&quot;&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;sfContext&lt;span&gt;::&lt;/span&gt;&lt;span&gt;hasInstance&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'frontend'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
    &lt;span&gt;&amp;#123;&lt;/span&gt;
      sfContext&lt;span&gt;::&lt;/span&gt;&lt;span&gt;createInstance&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;$this&lt;/span&gt;&lt;span&gt;-&amp;amp;&lt;/span&gt;gt&lt;span&gt;;&lt;/span&gt;projectConfiguration&lt;span&gt;-&amp;amp;&lt;/span&gt;gt&lt;span&gt;;&lt;/span&gt;getApplicationConfiguration&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'frontend'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'test'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;true&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
    &lt;span&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So wird die Instanz nur noch erzeugt, wenn es noch keine gibt.&lt;/p&gt;
&lt;p&gt;Ich werde mir meine TestCases immer wieder ansehen. Sollte ich dabei feststellen, dass ich diesen Schnipsel mehr als nur wenige Male verwende, dann werde ich ihn wohl in die &lt;a title=&quot;PHPUnit Sharing Fixture&quot; href=&quot;http://www.phpunit.de/manual/current/en/fixtures.html#fixtures.sharing-fixture&quot; target=&quot;_blank&quot;&gt;setUp() Methode der TestSuite&lt;/a&gt; umziehen, die kann dann f&#252;r alle Tests was vorbereiten.&lt;/p&gt;
&lt;p&gt;So, ich bin erstmal zufrieden mit mir. Der Release Tag kommt n&#228;her! &lt;img src=&quot;http://test.ical.ly/wp-includes/images/smilies/icon_smile.gif&quot; alt=&quot;:)&quot; class=&quot;wp-smiley&quot; /&gt; &lt;/p&gt;


&lt;!-- Begin SexyBookmarks Menu Code --&gt;
&lt;div class=&quot;sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-german&quot;&gt;
&lt;ul class=&quot;socials&quot;&gt;
		&lt;li class=&quot;sexy-twitter&quot;&gt;
			&lt;a href=&quot;http://twitter.com/home?status=Mehr+zu+PHPUnit+Tests+in+symfony+Plugins+-+http://b2l.me/jpy7p+(via+@testically)&amp;source=shareaholic&quot; rel=&quot;nofollow&quot; title=&quot;Twittere diesen Artikel!&quot;&gt;Twittere diesen Artikel!&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-delicious&quot;&gt;
			&lt;a href=&quot;http://delicious.com/post?url=http://test.ical.ly/2010/03/11/mehr-zu-phpunit-tests-in-symfony-plugins/&amp;title=Mehr+zu+PHPUnit+Tests+in+symfony+Plugins&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei del.icio.us&quot;&gt;Empfehle diesen Artikel bei del.icio.us&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-reddit&quot;&gt;
			&lt;a href=&quot;http://reddit.com/submit?url=http://test.ical.ly/2010/03/11/mehr-zu-phpunit-tests-in-symfony-plugins/&amp;title=Mehr+zu+PHPUnit+Tests+in+symfony+Plugins&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Reddit&quot;&gt;Empfehle diesen Artikel bei Reddit&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-stumbleupon&quot;&gt;
			&lt;a href=&quot;http://www.stumbleupon.com/submit?url=http://test.ical.ly/2010/03/11/mehr-zu-phpunit-tests-in-symfony-plugins/&amp;title=Mehr+zu+PHPUnit+Tests+in+symfony+Plugins&quot; rel=&quot;nofollow&quot; title=&quot;Bei StumbleUpon einstellen&quot;&gt;Bei StumbleUpon einstellen&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-linkedin&quot;&gt;
			&lt;a href=&quot;http://www.linkedin.com/shareArticle?mini=true&amp;url=http://test.ical.ly/2010/03/11/mehr-zu-phpunit-tests-in-symfony-plugins/&amp;title=Mehr+zu+PHPUnit+Tests+in+symfony+Plugins&amp;summary=Gestern%20hab%20ich%20mich%20etwas%20dar%C3%BCber%20ausgelassen%2C%20wie%20doof%20doch%20einige%20Code%20Koppelungen%20von%20symfony%20mir%20das%20Testen%20behinderten.%0D%0A%0D%0AVor%20allem%20drei%20Dinge%20haben%20mir%20das%20Leben%20schwer%20gemacht%3A%20die%20Konfiguration%2C%20sfContext%20und%20Datenbankabh%C3%A4ngigkeiten.%C2%A0Und%20ich%20habe%20f%C3%BCr%20alle%20drei%20auch%20Antworten%20finden%20k%C3%B6&amp;source=test.ical.ly&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei LinkedIn&quot;&gt;Empfehle diesen Artikel bei LinkedIn&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-technorati&quot;&gt;
			&lt;a href=&quot;http://technorati.com/faves?add=http://test.ical.ly/2010/03/11/mehr-zu-phpunit-tests-in-symfony-plugins/&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Technorati&quot;&gt;Empfehle diesen Artikel bei Technorati&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-facebook&quot;&gt;
			&lt;a href=&quot;http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://test.ical.ly/2010/03/11/mehr-zu-phpunit-tests-in-symfony-plugins/&amp;t=Mehr+zu+PHPUnit+Tests+in+symfony+Plugins&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Facebook&quot;&gt;Empfehle diesen Artikel bei Facebook&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-google&quot;&gt;
			&lt;a href=&quot;http://test.ical.ly/2010/03/11/mehr-zu-phpunit-tests-in-symfony-plugins/&quot; rel=&quot;nofollow&quot; title=&quot;&quot;&gt;&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-misterwong&quot;&gt;
			&lt;a href=&quot;http://www.mister-wong.de/addurl/?bm_url=http://test.ical.ly/2010/03/11/mehr-zu-phpunit-tests-in-symfony-plugins/&amp;bm_description=Mehr+zu+PHPUnit+Tests+in+symfony+Plugins&amp;plugin=sexybookmarks&quot; rel=&quot;nofollow&quot; title=&quot;F&#252;ge hinzu zu Mister Wong&quot;&gt;F&#252;ge hinzu zu Mister Wong&lt;/a&gt;
		&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;!-- End SexyBookmarks Menu Code --&gt;</content>
		<author>
			<name>Christian</name>
			<uri>http://test.ical.ly</uri>
		</author>
		<source>
			<title type="html">test.ical.ly &#187; phpUnit</title>
			<subtitle type="html">getting PHP by the balls</subtitle>
			<link rel="self" href="http://test.ical.ly/tags/phpunit/feed/atom/"/>
			<id>http://test.ical.ly/feed/atom/</id>
			<updated>2010-09-01T00:00:27+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Neues Feature, neue Tests, neue Erfahrungen</title>
		<link href="http://test.ical.ly/2010/03/08/neues-feature-neue-tests-neue-erfahrungen/"/>
		<id>http://test.ical.ly/?p=473</id>
		<updated>2010-03-23T12:16:43+00:00</updated>
		<content type="html">&lt;p&gt;&lt;img class=&quot;alignleft&quot; title=&quot;Unit Tests&quot; src=&quot;http://www.lispcast.com/wp-content/uploads/2008/01/woman-gets-tdd.png&quot; alt=&quot;&quot; width=&quot;198&quot; height=&quot;248&quot; /&gt;Ich bin am Wochenende wenigstens ein paar Stunden aktiv gewesen und habe meinem kleinen Projekt ein neues Feature hinzugef&#252;gt.&lt;/p&gt;
&lt;p&gt;Mit dem sfImageTransformExtraPlugin erweitere ich das bereits existierende symfony Plugin sfImageTransformPlugin um einen Konfigurations Layer sowie die M&#246;glichkeit, einen Webservice f&#252;r Thumbnail Generierung zu betreiben. Ich werde das Ganze in K&#252;rze auch auf der symfony Website als Open Source Plugin zur Verf&#252;gung stellen, bis dahin m&#246;chte ich aber eine bessere Testabdeckung erreichen.&lt;/p&gt;
&lt;p&gt;Und genau da bin ich jetzt gerade bei und sammel mal wieder eine Menge kleine Erkenntnisse.&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-473&quot;&gt;&lt;/span&gt;Bislang konnte ich vier kleinere Dinge erlernen. Ob man das dann schon als Best Practice ausloben soll, weiss ich noch nicht.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;PHPUnit Pfade sind relational zum aktuellen Arbeitsverzeichnis&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Das hatte ich schonmal erw&#228;hnt. Die Pfadangaben in der &lt;em&gt;phpunit.xml&lt;/em&gt; k&#246;nnen relativ angegeben werden. Das ist gut, denn so muss ich nicht wissen, wie die Umgebung aussieht, in der mein Code l&#228;uft.&lt;/p&gt;
&lt;p&gt;Aber! Die Pfade sind nicht &amp;#8211; wie ich erwartet h&#228;tte &amp;#8211; relativ zur &lt;em&gt;phpunit.xml&lt;/em&gt; Datei, sondern relativ zum aktuellen Arbeitsverzeichnis, also dem Verzeichnis, von dem aus ich den &lt;em&gt;phpunit&lt;/em&gt; Befehl angestossen habe.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;F&#252;r die symfony Plugin Entwicklung heisst das:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PHPUnit muss immer im Wurzelverzeichnis des Plugins ausgef&#252;hrt werden.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Wenn das nicht geht, weil z.B. eine &lt;em&gt;AllTests.php&lt;/em&gt; &#252;ber mehrere Plugins Tests ausf&#252;hrt, dann muss ich via PHP Code das aktuelle Arbeitsverzeichnis vor den Plugin TestSuiten entsprechend wechseln.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Stream Wrapper muss man anders testen&lt;/h2&gt;
&lt;p&gt;In meinem Plugin habe ich drei Stream Wrapper geschrieben, die eine Datei aus jeweils anderen Quellen holen kann.&lt;/p&gt;
&lt;p&gt;Ein Stream Wrapper ist eine einfache Klasse, allerdings mit einem Unterschied zu herk&#246;mmlichen Klassen. N&#228;mlich werden seine &#246;ffentlichen Methoden nicht von PHP Code, sondern von der PHP Runtime ausgef&#252;hrt.&#160;Vor allem die Instanzierung ist schwer nachzubilden.&lt;/p&gt;
&lt;p&gt;Mein Fazit ist daher folgendes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stream Wrapper sollten nicht instanziert werden, um dann ihre Methoden aufzurufen, sondern stattdessen sollten sie registriert und entsprechend benutzt werden.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ich registriere sie also via &lt;em&gt;stream_wrapper_register()&lt;/em&gt; und rufe dann auf dem registrierten Protokoll PHP Dateifunktionen wie &lt;em&gt;fopen()&lt;/em&gt; und Co.&lt;/p&gt;
&lt;h2&gt;Einheiten mit Doctrine Abh&#228;ngigkeit verlangen ein besonderes Setup&lt;/h2&gt;
&lt;p&gt;Bei dieser Thematik bin ich noch nicht ganz schl&#252;ssig. Einige meiner Klassen nutzen direkt oder indirekt Doctrine.&lt;/p&gt;
&lt;p&gt;Wenn ich hier Datenverarbeitende Methoden teste, kann es sein, dass ich eine Datenbank ben&#246;tige. Nicht sch&#246;n, aber eventuell akzeptabel. Ich empfehle hier folgendes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bei Test-Datenbanken ist SQLite zu bevorzugen, weil hierf&#252;r keine weiteren Services bereitgestellt werden m&#252;ssen, wenn die Tests z.B. auf einem Continuous Integration Server laufen.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Aber ich muss so in jedem Fall eine Menge machen:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Eine Datenbank konfigurieren (SQLite)&lt;/li&gt;
&lt;li&gt;Die Test-relevanten&#160;Tabellen anlegen und benutzbar machen (&lt;em&gt;Doctrine::createTablesFromArray(array(&amp;#8217;Model1&amp;#8242;, &amp;#8216;Model2&amp;#8242;, ..))&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Fixtures laden (&lt;em&gt;Doctrine::loadData()&lt;/em&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Meistens allerdings will man gar nicht die Datenbank Aktivit&#228;t testen sondern die Logik drumherum. Daf&#252;r ist dieser Ballast viel zu teuer, weil er die Ausf&#252;hrzeit der Tests verl&#228;ngert.&lt;/p&gt;
&lt;p&gt;Ein vorsichtiges Fazit ist daher folgendes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Alle zu testenden Methoden refaktorisieren, um ihre Abh&#228;ngigkeiten zu injizieren oder soweit wegzukapseln, dass sie f&#252;r die Tests m&#246;glichst optional, mindestens aber mockbar sind.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Das wird nicht einfach..&lt;/p&gt;
&lt;h2&gt;Das generierte Fixture Projekt in einem Plugin verursacht Schwierigkeiten in TestSuites&lt;/h2&gt;
&lt;p&gt;Wenn ich eine Plugin Struktur generiere, dann findet sich darin auch ein kleines symfony Projekt im &lt;em&gt;fixtures&lt;/em&gt; Verzeichnis. Dieses wird ben&#246;tigt, um ein Plugin auch unabh&#228;ngig von aktuellen Projekt Settings testen zu k&#246;nnen.&lt;/p&gt;
&lt;p&gt;Eines, was sich mir aber so garnicht erschliesst ist, dass im config Verzeichnis eine &lt;em&gt;ProjectConfiguration&lt;/em&gt; Klasse angelegt wird. Im richtigen Projekt heisst diese &lt;em&gt;sfProjectConfiguration&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Das Problem ist folgendes:&lt;/p&gt;
&lt;p&gt;Habe ich zwei Plugins, habe ich auch zwei gleichnamige Klassen. M&#246;chte ich die TestSuites beider Plugins in einer Projekt weiten &lt;em&gt;AllTests.php&lt;/em&gt; zusammenfassen, werden beide Klassen deklariert.&lt;/p&gt;
&lt;p&gt;Das kracht nat&#252;rlich (&lt;em&gt;can not redeclare class..&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;Ich umgehe das wie folgt:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nach dem Generieren einer Plugin Struktur ist die Datei ProjectConfiguration.class.php und die darin enthaltende Klasse umzubenennen in myPluginProjectConfiguration.class.php&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Damit sind dann die Namenskonflikte gel&#246;st.&lt;/p&gt;


&lt;!-- Begin SexyBookmarks Menu Code --&gt;
&lt;div class=&quot;sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-german&quot;&gt;
&lt;ul class=&quot;socials&quot;&gt;
		&lt;li class=&quot;sexy-twitter&quot;&gt;
			&lt;a href=&quot;http://twitter.com/home?status=Neues+Feature%2C+neue+Tests%2C+neue+Erfahrungen+-+http://b2l.me/jdg8v+(via+@testically)&amp;source=shareaholic&quot; rel=&quot;nofollow&quot; title=&quot;Twittere diesen Artikel!&quot;&gt;Twittere diesen Artikel!&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-delicious&quot;&gt;
			&lt;a href=&quot;http://delicious.com/post?url=http://test.ical.ly/2010/03/08/neues-feature-neue-tests-neue-erfahrungen/&amp;title=Neues+Feature%2C+neue+Tests%2C+neue+Erfahrungen&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei del.icio.us&quot;&gt;Empfehle diesen Artikel bei del.icio.us&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-reddit&quot;&gt;
			&lt;a href=&quot;http://reddit.com/submit?url=http://test.ical.ly/2010/03/08/neues-feature-neue-tests-neue-erfahrungen/&amp;title=Neues+Feature%2C+neue+Tests%2C+neue+Erfahrungen&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Reddit&quot;&gt;Empfehle diesen Artikel bei Reddit&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-stumbleupon&quot;&gt;
			&lt;a href=&quot;http://www.stumbleupon.com/submit?url=http://test.ical.ly/2010/03/08/neues-feature-neue-tests-neue-erfahrungen/&amp;title=Neues+Feature%2C+neue+Tests%2C+neue+Erfahrungen&quot; rel=&quot;nofollow&quot; title=&quot;Bei StumbleUpon einstellen&quot;&gt;Bei StumbleUpon einstellen&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-linkedin&quot;&gt;
			&lt;a href=&quot;http://www.linkedin.com/shareArticle?mini=true&amp;url=http://test.ical.ly/2010/03/08/neues-feature-neue-tests-neue-erfahrungen/&amp;title=Neues+Feature%2C+neue+Tests%2C+neue+Erfahrungen&amp;summary=Ich%20bin%20am%20Wochenende%20wenigstens%20ein%20paar%20Stunden%20aktiv%20gewesen%20und%20habe%20meinem%20kleinen%20Projekt%20ein%20neues%20Feature%20hinzugef%C3%BCgt.%0D%0A%0D%0AMit%20dem%20sfImageTransformExtraPlugin%20erweitere%20ich%20das%20bereits%20existierende%20symfony%20Plugin%20sfImageTransformPlugin%20um%20einen%20Konfigurations%20Layer%20sowie%20die%20M%C3%B6glichkeit%2C%20ei&amp;source=test.ical.ly&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei LinkedIn&quot;&gt;Empfehle diesen Artikel bei LinkedIn&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-technorati&quot;&gt;
			&lt;a href=&quot;http://technorati.com/faves?add=http://test.ical.ly/2010/03/08/neues-feature-neue-tests-neue-erfahrungen/&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Technorati&quot;&gt;Empfehle diesen Artikel bei Technorati&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-facebook&quot;&gt;
			&lt;a href=&quot;http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://test.ical.ly/2010/03/08/neues-feature-neue-tests-neue-erfahrungen/&amp;t=Neues+Feature%2C+neue+Tests%2C+neue+Erfahrungen&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Facebook&quot;&gt;Empfehle diesen Artikel bei Facebook&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-google&quot;&gt;
			&lt;a href=&quot;http://test.ical.ly/2010/03/08/neues-feature-neue-tests-neue-erfahrungen/&quot; rel=&quot;nofollow&quot; title=&quot;&quot;&gt;&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-misterwong&quot;&gt;
			&lt;a href=&quot;http://www.mister-wong.de/addurl/?bm_url=http://test.ical.ly/2010/03/08/neues-feature-neue-tests-neue-erfahrungen/&amp;bm_description=Neues+Feature%2C+neue+Tests%2C+neue+Erfahrungen&amp;plugin=sexybookmarks&quot; rel=&quot;nofollow&quot; title=&quot;F&#252;ge hinzu zu Mister Wong&quot;&gt;F&#252;ge hinzu zu Mister Wong&lt;/a&gt;
		&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;!-- End SexyBookmarks Menu Code --&gt;</content>
		<author>
			<name>Christian</name>
			<uri>http://test.ical.ly</uri>
		</author>
		<source>
			<title type="html">test.ical.ly &#187; phpUnit</title>
			<subtitle type="html">getting PHP by the balls</subtitle>
			<link rel="self" href="http://test.ical.ly/tags/phpunit/feed/atom/"/>
			<id>http://test.ical.ly/feed/atom/</id>
			<updated>2010-09-01T00:00:27+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Mein erstes Test-getriebenes Refactoring</title>
		<link href="http://test.ical.ly/2010/03/10/mein-erstes-test-getriebenes-refactoring/"/>
		<id>http://test.ical.ly/?p=502</id>
		<updated>2010-03-09T08:22:03+00:00</updated>
		<content type="html">&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/03/refactoring_poster-p228118789330102998tdcp_4001.jpg&quot;&gt;&lt;img class=&quot;size-full wp-image-505 alignleft&quot; title=&quot;refactoring_poster-p228118789330102998tdcp_400&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/03/refactoring_poster-p228118789330102998tdcp_4001.jpg&quot; alt=&quot;refactoring_poster-p228118789330102998tdcp_400&quot; width=&quot;240&quot; height=&quot;156&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/03/refactoring_poster-p228118789330102998tdcp_4001.jpg&quot;&gt;&lt;/a&gt;Nachdem ich seit gestern nun einigermassen mit Tests ausgestattet bin, will ich mich heute ans Refactoring machen.&lt;/p&gt;
&lt;p&gt;Eine Methode ist mir da besonders im Sinn, die ich als zu gross und zu prozedural empfinde. Sie macht einfach zu viel, was besser in mehreren kleinen Methoden erledigt werden sollte.&lt;/p&gt;
&lt;p&gt;Ausserdem habe ich noch zwei Methoden in derselben Klasse, die da nun wirklich nicht hingeh&#246;ren.&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-502&quot;&gt;&lt;/span&gt;Zun&#228;chst einmal will ich mich um diese angesprochene Methode k&#252;mmern, indem ich sie via &lt;a title=&quot;Extract Method&quot; href=&quot;http://www.refactoring.com/catalog/extractMethod.html&quot; target=&quot;_blank&quot;&gt;Extract Method&lt;/a&gt; in kleinere Einheiten zerlege.&lt;/p&gt;
&lt;p&gt;Hier ist sie vor dem Refaktorisieren.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/03/code_org.jpg&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-492&quot; title=&quot;code_org&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/03/code_org.jpg&quot; alt=&quot;code_org&quot; width=&quot;788&quot; height=&quot;1010&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Zugegeben mit 50 Zeilen stellt diese Methode sicher keine Rekorde in prozeduralen Spaghetti Code Wettbewerben auf.&lt;/p&gt;
&lt;p&gt;Trotzdem macht sie zu viel unterschiedliche Sachen, wie:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Parameter &#252;berpr&#252;fen&lt;/li&gt;
&lt;li&gt;eine Resource besorgen&lt;/li&gt;
&lt;li&gt;mit Konfiguration hantieren&lt;/li&gt;
&lt;li&gt;einen Mimetypen setzen&lt;/li&gt;
&lt;li&gt;&#252;ber Transformationseinstellungen iterieren&lt;/li&gt;
&lt;li&gt;jeweils einen Adapter aktualisieren&lt;/li&gt;
&lt;li&gt;jeweils die Parameter vorbereiten&lt;/li&gt;
&lt;li&gt;jeweils die Transformationen ausf&#252;hren&lt;/li&gt;
&lt;li&gt;die Qualit&#228;t setzen&lt;/li&gt;
&lt;li&gt;die Bild Resource zur&#252;ckgeben.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Und da die benutzten Klassen und Methoden jeweils dynamisch zusammengesetzt werden, gibt es in der Mitte einen riesen Berg an Magie, den ich nicht so gerne anfasse.&lt;/p&gt;
&lt;p&gt;Das will ich aber, denn die Transformation-abh&#228;ngigen prepareParametersFor..() Methoden sind aktuell Methoden an dieser Klasse, statt als Callback aufgerufen an den entsprechenden Transformationen zu h&#228;ngen. Das w&#228;re sinnvoller f&#252;r die Entwicklung von Transformations, denn eine solche Methode w&#228;re dann dort verortet, wo auch der Rest der Implementierung ist.&lt;/p&gt;
&lt;p&gt;Aber dazu will ich erst alles in verdaubare Einheiten aufteilen. Also los.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/03/code_extract_transform2.jpg&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-494&quot; title=&quot;code_extract_transform2&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/03/code_extract_transform2.jpg&quot; alt=&quot;code_extract_transform2&quot; width=&quot;699&quot; height=&quot;498&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hier habe ich den Teil der &#252;ber die Settings iteriert herausgel&#246;st und in eine eigene Methode gepackt.&lt;/p&gt;
&lt;p&gt;In der alten Methode habe ich diesen Teil durch einen entsprechenden Aufruf ersetzt.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/03/code_extract_transform1.jpg&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-495&quot; title=&quot;code_extract_transform1&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/03/code_extract_transform1.jpg&quot; alt=&quot;code_extract_transform1&quot; width=&quot;604&quot; height=&quot;116&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Jetzt gleich meinen PHPUnit Test ausgef&#252;hrt und sichergestellt, dass noch alles l&#228;uft. Tut es, weiter.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/03/code_extract_setAdapter2.jpg&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-496&quot; title=&quot;code_extract_setAdapter2&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/03/code_extract_setAdapter2.jpg&quot; alt=&quot;code_extract_setAdapter2&quot; width=&quot;706&quot; height=&quot;255&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Den Teil der den Adapter setzt habe ich auch in eine eigene Methode verpackt und nur noch aufgerufen. Das hat mir auch gleich noch eine lokale Variable gespart.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/03/code_extract_setAdapter1.jpg&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-497&quot; title=&quot;code_extract_setAdapter1&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/03/code_extract_setAdapter1.jpg&quot; alt=&quot;code_extract_setAdapter1&quot; width=&quot;660&quot; height=&quot;98&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Wieder den Test ausf&#252;hren, l&#228;uft.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/03/code_extract_prepareParameters2.jpg&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-498&quot; title=&quot;code_extract_prepareParameters2&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/03/code_extract_prepareParameters2.jpg&quot; alt=&quot;code_extract_prepareParameters2&quot; width=&quot;779&quot; height=&quot;323&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Die Parameter Vorbereitung habe ich dann ebenso separiert und lediglich aufgerufen.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/03/code_extract_prepareParameters1.jpg&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-499&quot; title=&quot;code_extract_prepareParameters1&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/03/code_extract_prepareParameters1.jpg&quot; alt=&quot;code_extract_prepareParameters1&quot; width=&quot;984&quot; height=&quot;17&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Die erste extrahierte Methode transform() konnte ich dann noch um zwei weitere lokale Variablen entlasten und auf folgende Gr&#246;sse verschlanken.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/03/code_extract_transform_final.jpg&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-493&quot; title=&quot;code_extract_transform_final&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/03/code_extract_transform_final.jpg&quot; alt=&quot;code_extract_transform_final&quot; width=&quot;981&quot; height=&quot;244&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nat&#252;rlich habe ich auch jetzt wieder getestet!&lt;/p&gt;
&lt;p&gt;Nach dieser Aktion habe ich drei Methoden extrahiert. Sicher noch nicht das Ende des M&#246;glichen, aber genug f&#252;r meine Zwecke, denn ich will ja die Vorbereitungs Methoden extrahieren.&lt;/p&gt;
&lt;p&gt;Dazu habe ich alle &lt;em&gt;prepareParametersFor..()&lt;/em&gt; Methoden, die hier &lt;em&gt;private&lt;/em&gt; Member waren via &lt;a title=&quot;Move Method&quot; href=&quot;http://www.refactoring.com/catalog/moveMethod.html&quot; target=&quot;_blank&quot;&gt;Move Method&lt;/a&gt; in die entsprechenden Transformations Klassen geworfen und dort via &lt;a title=&quot;Rename Method&quot; href=&quot;http://www.refactoring.com/catalog/renameMethod.html&quot; target=&quot;_blank&quot;&gt;Rename Method&lt;/a&gt; in&lt;em&gt; prepareParameters()&lt;/em&gt; umbenannt. Statt &lt;em&gt;private&lt;/em&gt; sind sie nun &lt;em&gt;public static&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Nun musste ich nat&#252;rlich noch die aufrufende &lt;em&gt;prepareParameters()&lt;/em&gt; Methode so umschreiben, dass sie statt der lokalen Methoden die externen benutzt.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/03/code_extract_prepareParametersfinal.jpg&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-504&quot; title=&quot;code_extract_prepareParametersfinal&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/03/code_extract_prepareParametersfinal.jpg&quot; alt=&quot;code_extract_prepareParametersfinal&quot; width=&quot;898&quot; height=&quot;433&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Noch einmal die Tests durchlaufen lassen und fertig sind wir!&lt;/p&gt;
&lt;p&gt;Nat&#252;rlich sind meine Tests nicht immer durchgelaufen. Ich habe gen&#252;gend kleine Fehler gemacht. Aber durch ein h&#228;ufiges Ausf&#252;hren der Tests, lagen die zu den Fehlern f&#252;hrenden &#196;nderungen nie allzu lange zur&#252;ck, so dass ich sie leicht korrigieren konnte.&lt;/p&gt;
&lt;p&gt;Wenn man sich dieses Beispiel so anschaut, sieht es nun wirklich nicht besonders schwierig aus. Aber ich habe es vor ein paar Wochen mal ohne Tests versucht und nach zwei Stunden alles wieder abgeblasen, weil ich mich st&#228;ndig verfranst hatte. Jetzt hat es circa eine Stunde gedauert und alles war fertig inklusive DocComments.&lt;/p&gt;
&lt;p&gt;Ich sehe das jetzt mal als meine erste wirkliche Testerfahrung unter Realbedingungen an und sie ist durchweg positiv!&lt;/p&gt;


&lt;!-- Begin SexyBookmarks Menu Code --&gt;
&lt;div class=&quot;sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-german&quot;&gt;
&lt;ul class=&quot;socials&quot;&gt;
		&lt;li class=&quot;sexy-twitter&quot;&gt;
			&lt;a href=&quot;http://twitter.com/home?status=Mein+erstes+Test-getriebenes+Refactoring+-+http://b2l.me/jkkw3+(via+@testically)&amp;source=shareaholic&quot; rel=&quot;nofollow&quot; title=&quot;Twittere diesen Artikel!&quot;&gt;Twittere diesen Artikel!&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-delicious&quot;&gt;
			&lt;a href=&quot;http://delicious.com/post?url=http://test.ical.ly/2010/03/10/mein-erstes-test-getriebenes-refactoring/&amp;title=Mein+erstes+Test-getriebenes+Refactoring&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei del.icio.us&quot;&gt;Empfehle diesen Artikel bei del.icio.us&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-reddit&quot;&gt;
			&lt;a href=&quot;http://reddit.com/submit?url=http://test.ical.ly/2010/03/10/mein-erstes-test-getriebenes-refactoring/&amp;title=Mein+erstes+Test-getriebenes+Refactoring&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Reddit&quot;&gt;Empfehle diesen Artikel bei Reddit&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-stumbleupon&quot;&gt;
			&lt;a href=&quot;http://www.stumbleupon.com/submit?url=http://test.ical.ly/2010/03/10/mein-erstes-test-getriebenes-refactoring/&amp;title=Mein+erstes+Test-getriebenes+Refactoring&quot; rel=&quot;nofollow&quot; title=&quot;Bei StumbleUpon einstellen&quot;&gt;Bei StumbleUpon einstellen&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-linkedin&quot;&gt;
			&lt;a href=&quot;http://www.linkedin.com/shareArticle?mini=true&amp;url=http://test.ical.ly/2010/03/10/mein-erstes-test-getriebenes-refactoring/&amp;title=Mein+erstes+Test-getriebenes+Refactoring&amp;summary=%0D%0A%0D%0ANachdem%20ich%20seit%20gestern%20nun%20einigermassen%20mit%20Tests%20ausgestattet%20bin%2C%20will%20ich%20mich%20heute%20ans%20Refactoring%20machen.%0D%0A%0D%0AEine%20Methode%20ist%20mir%20da%20besonders%20im%20Sinn%2C%20die%20ich%20als%20zu%20gross%20und%20zu%20prozedural%20empfinde.%20Sie%20macht%20einfach%20zu%20viel%2C%20was%20besser%20in%20mehreren%20kleinen%20Methoden%20erledigt%20werden%20sol&amp;source=test.ical.ly&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei LinkedIn&quot;&gt;Empfehle diesen Artikel bei LinkedIn&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-technorati&quot;&gt;
			&lt;a href=&quot;http://technorati.com/faves?add=http://test.ical.ly/2010/03/10/mein-erstes-test-getriebenes-refactoring/&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Technorati&quot;&gt;Empfehle diesen Artikel bei Technorati&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-facebook&quot;&gt;
			&lt;a href=&quot;http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://test.ical.ly/2010/03/10/mein-erstes-test-getriebenes-refactoring/&amp;t=Mein+erstes+Test-getriebenes+Refactoring&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Facebook&quot;&gt;Empfehle diesen Artikel bei Facebook&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-google&quot;&gt;
			&lt;a href=&quot;http://test.ical.ly/2010/03/10/mein-erstes-test-getriebenes-refactoring/&quot; rel=&quot;nofollow&quot; title=&quot;&quot;&gt;&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-misterwong&quot;&gt;
			&lt;a href=&quot;http://www.mister-wong.de/addurl/?bm_url=http://test.ical.ly/2010/03/10/mein-erstes-test-getriebenes-refactoring/&amp;bm_description=Mein+erstes+Test-getriebenes+Refactoring&amp;plugin=sexybookmarks&quot; rel=&quot;nofollow&quot; title=&quot;F&#252;ge hinzu zu Mister Wong&quot;&gt;F&#252;ge hinzu zu Mister Wong&lt;/a&gt;
		&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;!-- End SexyBookmarks Menu Code --&gt;</content>
		<author>
			<name>Christian</name>
			<uri>http://test.ical.ly</uri>
		</author>
		<source>
			<title type="html">test.ical.ly &#187; phpUnit</title>
			<subtitle type="html">getting PHP by the balls</subtitle>
			<link rel="self" href="http://test.ical.ly/tags/phpunit/feed/atom/"/>
			<id>http://test.ical.ly/feed/atom/</id>
			<updated>2010-09-01T00:00:27+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Alles neu in Symfony 2.0. Jetzt auch das Testen mit PHPUnit!</title>
		<link href="http://test.ical.ly/2010/02/24/alles-neu-in-symfony-2-0-jetzt-auch-das-testen-mit-phpunit/"/>
		<id>http://test.ical.ly/?p=411</id>
		<updated>2010-02-24T08:21:41+00:00</updated>
		<content type="html">&lt;p&gt;Gerade erst gestern habe ich mich hier &lt;a title=&quot;Alles neu in Symfony 2.0, auch das Testen?&quot; href=&quot;http://test.ical.ly/2010/02/23/alles-neu-in-symfony-2-0-auch-das-testen/&quot; target=&quot;_blank&quot;&gt;&#246;ffentlich gewundert&lt;/a&gt;, warum das Thema Testing auf der Symfony Live 2010 keine Rolle spielte als Symfony 2.0 enth&#252;llt wurde. In den Sourcen von Symfony 2.0 war nur lime bzw. Lime2 zu entdecken.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/02/Twitter.jpg&quot;&gt;&lt;img class=&quot;alignnone size-full wp-image-417&quot; title=&quot;Twitter&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/02/Twitter.jpg&quot; alt=&quot;Twitter&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nun scheint die Antwort gefunden zu sein.&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-411&quot;&gt;&lt;/span&gt;Benjamin Eberlei, seines Zeichens beteiligt am Zend Framework und Doctrine, machte mich gestern darauf aufmerksam, dass erst am vergangenen Wochenende eine Entscheidung zum Thema Testing gefallen sei.&lt;/p&gt;
&lt;h2&gt;Symfony 2.0 wird auf PHPUnit umsteigen!&lt;/h2&gt;
&lt;p&gt;Ich habe mir tats&#228;chlich mal die M&#252;he gemacht, ein wenig auf GitHub herumzuschauen, ob denn da irgendein Commit zu finden ist, der diese Entscheidung best&#228;tigt.&lt;/p&gt;
&lt;p&gt;Nichts im &lt;a title=&quot;Symfony GitHub Repository&quot; href=&quot;http://github.com/symfony/symfony&quot; target=&quot;_blank&quot;&gt;Symfony Repository&lt;/a&gt;, nichts bei &lt;a title=&quot;FabPot auf GitHub&quot; href=&quot;http://github.com/fabpot/symfony&quot; target=&quot;_blank&quot;&gt;Fabien &lt;/a&gt;aber dann doch was!&lt;/p&gt;
&lt;p&gt;Unter &lt;a title=&quot;Symfony 2 Testing Conventions&quot; href=&quot;https://gist.github.com/309820/59a86f8637e9ce85c17daf57317922f597c4569e&quot; target=&quot;_blank&quot;&gt;dieser URL&lt;/a&gt; gibt es die &lt;em&gt;Symfony 2 Testing Conventions&lt;/em&gt; zu finden. Darin ist nur noch von &lt;em&gt;PHPUnit &lt;/em&gt;die Rede!&lt;/p&gt;
&lt;p&gt;Was mich auch freut ist, dass es sich dabei um Commits von Bernhard Schussek handelt und man wohl davon ausgehen kann, dass hier niemand vor den Kopf gestossen wurde. Immerhin war er die treibende Kraft hinter &lt;em&gt;Lime2&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Ich finde es toll, dass sich Symfony mit der Verwendung zuerst einiger Zend Framework Komponenten und jetzt von PHPUnit immer mehr &amp;#8220;fremden&amp;#8221; PHP Standards &#246;ffnet.&lt;/p&gt;
&lt;p&gt;Hier nochmal f&#252;r alle zum Nachlesen. Was daraus zu lernen ist, werde ich mir ein anderes mal ansehen.&lt;/p&gt;
&lt;h1&gt;Symfony 2 Testing Conventions&lt;/h1&gt;
&lt;p&gt;
&lt;p&gt;Symfony 2 is programmatically tested using unit tests. You can read more about&#160;&lt;a href=&quot;http://en.wikipedia.org/wiki/Unit_testing&quot;&gt;unit testing on Wikipedia&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Test Organization&lt;/h2&gt;
&lt;h3&gt;Directory Structure&lt;/h3&gt;
&lt;p&gt;The&#160;&lt;code&gt;src/&lt;/code&gt; directory contains the three subdirectories&#160;&lt;code&gt;Components/&lt;/code&gt;,&#160;&lt;code&gt;Foundation/&lt;/code&gt; and&#160;&lt;code&gt;Framework/&lt;/code&gt;, which contains the core bundles. The components and core bundles should have a subdirectory&#160;&lt;code&gt;Tests/&lt;/code&gt; which contains all the tests for the component/bundle. The foundation tests belong in the subdirectory&#160;&lt;code&gt;Tests/&lt;/code&gt; of the&#160;&lt;code&gt;Foundation/&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;Some examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src/Symfony/Components/EventDispatcher/EventDispatcher.php&lt;/code&gt; should be tested in&lt;code&gt;src/Symfony/Components/EventDispatcher/Tests/EventDispatcherTest.php&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/Symfony/Framework/WebBundle/User.php&lt;/code&gt; should be tested in&#160;&lt;code&gt;src/Symfony/Framework/WebBundle/Tests/UserTest.php&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/Symfony/Foundation/ClassLoader.php&lt;/code&gt; should be tested in&#160;&lt;code&gt;src/Symfony/Foundation/Tests/ClassLoaderTest.php&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The subdirectory structure in the&#160;&lt;code&gt;Tests/&lt;/code&gt; directories should match the directory structure of the classes.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src/Symfony/Foundation/Bundle/Bundle.php&lt;/code&gt; should be tested in&#160;&lt;code&gt;src/Symfony/Foundation/Tests/Bundle/BundleTest.php&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Namespaces&lt;/h3&gt;
&lt;p&gt;The namespaces of the test classes should match their directory structure.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The namespace of&#160;&lt;code&gt;src/Symfony/Foundation/Tests/Bundle/BundleTest.php&lt;/code&gt; is&#160;&lt;strong&gt;Symfony\Foundation\Tests\Bundle&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Test Suites&lt;/h3&gt;
&lt;p&gt;Every&#160;&lt;code&gt;Tests/&lt;/code&gt; directory should contain a&#160;&lt;strong&gt;configuration.xml&lt;/strong&gt; file that tells PHPUnit where to find the test classes. You can use the following template for a new component or bundle.&lt;/p&gt;
&lt;h3&gt;Test Classes&lt;/h3&gt;
&lt;p&gt;Test classes should have the suffix&#160;&lt;strong&gt;Test&lt;/strong&gt; and generally inherit&#160;&lt;code&gt;PHPUnit_Framework_TestCase&lt;/code&gt;. The name of a test class should refer to a class or the state or aspect of a class.&lt;/p&gt;
&lt;p&gt;Some examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;FormFieldTest&lt;/strong&gt; is a good name because it refers to the&#160;&lt;code&gt;FormField&lt;/code&gt; class&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FormFieldUnboundTest&lt;/strong&gt; is a good name because it refers to the &amp;#8220;unbound&amp;#8221; state of the&#160;&lt;code&gt;FormField&lt;/code&gt; class&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FormFieldCreate&lt;/strong&gt; is a bad name, because it&amp;#8217;s too generic&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Test Methods&lt;/h3&gt;
&lt;p&gt;Methods should support agile documentation and should be named so that if it fails, it is obvious what failed. They should also give information of the system they test&lt;/p&gt;
&lt;p&gt;For example the method test name&#160;&lt;strong&gt;testBindInvalidData()&lt;/strong&gt; is a good name.&lt;/p&gt;
&lt;p&gt;Test method names can be long, but the method content should not be. If you need several assert-calls, divide the method into smaller methods. There should never be assertions within any loops, and rarely within functions.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; Commonly used testing method naming convention&#160;&lt;strong&gt;test[methodName]&lt;/strong&gt; is not allowed in Symfony 2. So in this case&lt;strong&gt;testBind()&lt;/strong&gt; would not be allowed!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Test Fixtures&lt;/h3&gt;
&lt;p&gt;Shared test fixtures should be set up and deleted in the methods&#160;&lt;strong&gt;setUp()&lt;/strong&gt; and&#160;&lt;strong&gt;tearDown()&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Running Tests&lt;/h2&gt;
&lt;p&gt;Tests can be executed via the&#160;&lt;code&gt;phpunit&lt;/code&gt; command. If you have not already,&#160;&lt;a href=&quot;http://www.phpunit.de/manual/current/en/installation.html&quot;&gt;install PHPUnit via PEAR&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Then you can execute all tests of Symfony 2:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ phpunit --configuration=src/Symfony/Tests/configuration.xml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also execute the tests of the foundation or of a specific component or bundle:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ phpunit src/Symfony/Foundation/Tests/AllTests.php
$ phpunit src/Symfony/Components/EventDispatcher/Tests/AllTests.php
$ phpunit src/Symfony/Framework/WebBundle/Tests/AllTests.php
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last option is to execute the tests of all components or all core bundles:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ phpunit src/Symfony/Components/Tests/AllTests.php
$ phpunit src/Symfony/Framework/Tests/AllTests.php&lt;/code&gt;&lt;/pre&gt;


&lt;!-- Begin SexyBookmarks Menu Code --&gt;
&lt;div class=&quot;sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-german&quot;&gt;
&lt;ul class=&quot;socials&quot;&gt;
		&lt;li class=&quot;sexy-twitter&quot;&gt;
			&lt;a href=&quot;http://twitter.com/home?status=Alles+neu+in+Symfony+2.0.+Jetzt+auch+das+Testen+mit+PHPUnit%21+-+http://b2l.me/g74vc+(via+@testically)&amp;source=shareaholic&quot; rel=&quot;nofollow&quot; title=&quot;Twittere diesen Artikel!&quot;&gt;Twittere diesen Artikel!&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-delicious&quot;&gt;
			&lt;a href=&quot;http://delicious.com/post?url=http://test.ical.ly/2010/02/24/alles-neu-in-symfony-2-0-jetzt-auch-das-testen-mit-phpunit/&amp;title=Alles+neu+in+Symfony+2.0.+Jetzt+auch+das+Testen+mit+PHPUnit%21&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei del.icio.us&quot;&gt;Empfehle diesen Artikel bei del.icio.us&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-reddit&quot;&gt;
			&lt;a href=&quot;http://reddit.com/submit?url=http://test.ical.ly/2010/02/24/alles-neu-in-symfony-2-0-jetzt-auch-das-testen-mit-phpunit/&amp;title=Alles+neu+in+Symfony+2.0.+Jetzt+auch+das+Testen+mit+PHPUnit%21&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Reddit&quot;&gt;Empfehle diesen Artikel bei Reddit&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-stumbleupon&quot;&gt;
			&lt;a href=&quot;http://www.stumbleupon.com/submit?url=http://test.ical.ly/2010/02/24/alles-neu-in-symfony-2-0-jetzt-auch-das-testen-mit-phpunit/&amp;title=Alles+neu+in+Symfony+2.0.+Jetzt+auch+das+Testen+mit+PHPUnit%21&quot; rel=&quot;nofollow&quot; title=&quot;Bei StumbleUpon einstellen&quot;&gt;Bei StumbleUpon einstellen&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-linkedin&quot;&gt;
			&lt;a href=&quot;http://www.linkedin.com/shareArticle?mini=true&amp;url=http://test.ical.ly/2010/02/24/alles-neu-in-symfony-2-0-jetzt-auch-das-testen-mit-phpunit/&amp;title=Alles+neu+in+Symfony+2.0.+Jetzt+auch+das+Testen+mit+PHPUnit%21&amp;summary=Gerade%20erst%20gestern%20habe%20ich%20mich%20hier%20%C3%B6ffentlich%20gewundert%2C%20warum%20das%20Thema%20Testing%20auf%20der%20Symfony%20Live%202010%20keine%20Rolle%20spielte%20als%20Symfony%202.0%20enth%C3%BCllt%20wurde.%20In%20den%20Sourcen%20von%20Symfony%202.0%20war%20nur%20lime%20bzw.%20Lime2%20zu%20entdecken.%0D%0A%0D%0A%0D%0A%0D%0ANun%20scheint%20die%20Antwort%20gefunden%20zu%20sein.%0D%0A%0D%0ABenjamin%20Eberl&amp;source=test.ical.ly&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei LinkedIn&quot;&gt;Empfehle diesen Artikel bei LinkedIn&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-technorati&quot;&gt;
			&lt;a href=&quot;http://technorati.com/faves?add=http://test.ical.ly/2010/02/24/alles-neu-in-symfony-2-0-jetzt-auch-das-testen-mit-phpunit/&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Technorati&quot;&gt;Empfehle diesen Artikel bei Technorati&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-facebook&quot;&gt;
			&lt;a href=&quot;http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://test.ical.ly/2010/02/24/alles-neu-in-symfony-2-0-jetzt-auch-das-testen-mit-phpunit/&amp;t=Alles+neu+in+Symfony+2.0.+Jetzt+auch+das+Testen+mit+PHPUnit%21&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Facebook&quot;&gt;Empfehle diesen Artikel bei Facebook&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-google&quot;&gt;
			&lt;a href=&quot;http://test.ical.ly/2010/02/24/alles-neu-in-symfony-2-0-jetzt-auch-das-testen-mit-phpunit/&quot; rel=&quot;nofollow&quot; title=&quot;&quot;&gt;&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-misterwong&quot;&gt;
			&lt;a href=&quot;http://www.mister-wong.de/addurl/?bm_url=http://test.ical.ly/2010/02/24/alles-neu-in-symfony-2-0-jetzt-auch-das-testen-mit-phpunit/&amp;bm_description=Alles+neu+in+Symfony+2.0.+Jetzt+auch+das+Testen+mit+PHPUnit%21&amp;plugin=sexybookmarks&quot; rel=&quot;nofollow&quot; title=&quot;F&#252;ge hinzu zu Mister Wong&quot;&gt;F&#252;ge hinzu zu Mister Wong&lt;/a&gt;
		&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;!-- End SexyBookmarks Menu Code --&gt;&lt;/p&gt;</content>
		<author>
			<name>Christian</name>
			<uri>http://test.ical.ly</uri>
		</author>
		<source>
			<title type="html">test.ical.ly &#187; phpUnit</title>
			<subtitle type="html">getting PHP by the balls</subtitle>
			<link rel="self" href="http://test.ical.ly/tags/phpunit/feed/atom/"/>
			<id>http://test.ical.ly/feed/atom/</id>
			<updated>2010-09-01T00:00:27+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Stubbing Hard-Coded Dependencies</title>
		<link href="http://sebastian-bergmann.de/archives/885-Stubbing-Hard-Coded-Dependencies.html"/>
		<id>http://sebastian-bergmann.de/archives/885-guid.html</id>
		<updated>2010-02-16T07:00:00+00:00</updated>
		<content type="html">&lt;p&gt;&lt;strong&gt;This article is part of a series on testing untestable code:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://sebastian-bergmann.de/archives/881-Testing-Your-Privates.html&quot;&gt;Testing private methods&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sebastian-bergmann.de/archives/882-Testing-Code-That-Uses-Singletons.html&quot;&gt;Testing code that uses singletons&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sebastian-bergmann.de/archives/883-Stubbing-and-Mocking-Static-Methods.html&quot;&gt;Stubbing static methods&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sebastian-bergmann.de/archives/885-Stubbing-Hard-Coded-Dependencies.html&quot;&gt;Stubbing hard-coded dependencies&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/p&gt;
&lt;p&gt;In a &lt;a href=&quot;http://en.wikipedia.org/wiki/Unit_test&quot;&gt;unit test&lt;/a&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/Mock_Object&quot;&gt;mock objects&lt;/a&gt; can simulate the behavior of complex, real (non-mock) objects and are therefore useful when a real object is difficult or impossible to incorporate into a unit test.&lt;/p&gt;
&lt;p&gt;A mock object can be used anywhere in the program where the program expects an object of the mocked class. However, this only works as long as the object can be passed into the context where the original object is used.&lt;/p&gt;
&lt;p&gt;Consider the following example:&lt;/p&gt;
&lt;dl&gt;&lt;dd&gt;&lt;pre class=&quot;programlisting&quot;&gt;&lt;code&gt;&lt;span class=&quot;default&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;require_once&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'Bar.php'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Foo&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;//&amp;#160;...&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$bar&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Bar&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$bar&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;doSomethingElse&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;//&amp;#160;...&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;TRUE&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/dd&gt;&lt;/dl&gt;

&lt;dl&gt;&lt;dd&gt;&lt;pre class=&quot;programlisting&quot;&gt;&lt;code&gt;&lt;span class=&quot;default&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Bar&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;doSomethingElse&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'*'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/dd&gt;&lt;/dl&gt;
&lt;p&gt;With the code above, it is impossible to run a unit test for the &lt;code&gt;Foo::doSomething()&lt;/code&gt; method without also creating an object of &lt;code&gt;Bar&lt;/code&gt;. As the method creates the object of &lt;code&gt;Bar&lt;/code&gt; itself, we cannot inject a mock object in its stead.&lt;/p&gt;
&lt;p&gt;In a perfect world, code such as the above could be refactored using &lt;a href=&quot;http://en.wikipedia.org/wiki/Dependency_Injection&quot;&gt;Dependency Injection&lt;/a&gt;:&lt;/p&gt;
&lt;dl&gt;&lt;dd&gt;&lt;pre class=&quot;programlisting&quot;&gt;&lt;code&gt;&lt;span class=&quot;default&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;require_once&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'Bar.php'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Foo&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Bar&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$bar&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$bar&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;===&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$bar&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Bar&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;//&amp;#160;...&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$bar&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;doSomethingElse&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;//&amp;#160;...&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;TRUE&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/dd&gt;&lt;/dl&gt;
&lt;p&gt;Unfortunately, this is not always possible (not because of technical reasons, though).&lt;/p&gt;
&lt;p&gt;This is where the &lt;code&gt;set_new_overload()&lt;/code&gt; function that is provided by the &lt;a href=&quot;http://github.com/sebastianbergmann/php-test-helpers&quot;&gt;test_helpers&lt;/a&gt; extension for the PHP Interpreter comes into play. It can be used to register a &lt;a href=&quot;http://www.php.net/manual/en/language.pseudo-types.php&quot;&gt;callback&lt;/a&gt; that is automatically invoked when the &lt;code&gt;new&lt;/code&gt; operator is executed:&lt;/p&gt;
&lt;dl&gt;&lt;dd&gt;&lt;pre class=&quot;programlisting&quot;&gt;&lt;code&gt;&lt;span class=&quot;default&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;require_once&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'Foo.php'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;FooTest&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;PHPUnit_Framework_TestCase&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;protected&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;setUp&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;getMock&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'Bar'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;/*&amp;#160;name&amp;#160;of&amp;#160;class&amp;#160;to&amp;#160;mock&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;*/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'doSomethingElse'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;/*&amp;#160;list&amp;#160;of&amp;#160;methods&amp;#160;to&amp;#160;mock&amp;#160;&amp;#160;&amp;#160;*/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;/*&amp;#160;constructor&amp;#160;arguments&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;*/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'BarMock'&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;/*&amp;#160;name&amp;#160;for&amp;#160;mocked&amp;#160;class&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;*/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;set_new_overload&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'newCallback'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;protected&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;tearDown&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;unset_new_overload&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;protected&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;newCallback&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$className&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;switch&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$className&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;case&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'Bar'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'BarMock'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$className&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;testDoSomething&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$foo&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;assertTrue&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$foo&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/dd&gt;&lt;/dl&gt;
&lt;p&gt;Lets run this unit test:&lt;/p&gt;
&lt;dl&gt;&lt;dd&gt;&lt;pre&gt;PHPUnit 3.4.10 by Sebastian Bergmann.

.

Time: 0 seconds, Memory: 7.50Mb

OK (1 test, 2 assertions)&lt;/pre&gt;&lt;/dd&gt;&lt;/dl&gt;

&lt;p&gt;Note that there is no &lt;code&gt;*&lt;/code&gt; (printed from &lt;code&gt;Bar::doSomethingElse()&lt;/code&gt;) in the output above.&lt;/p&gt;</content>
		<author>
			<name>Sebastian Bergmann</name>
			<email>nospam@example.com</email>
			<uri>http://sebastian-bergmann.de/</uri>
		</author>
		<source>
			<title type="html">Sebastian Bergmann - PHPUnit</title>
			<link rel="self" href="http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss"/>
			<id>http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss</id>
			<updated>2010-08-19T08:00:26+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Sharing Fixture Between Tests</title>
		<link href="http://sebastian-bergmann.de/archives/884-Sharing-Fixture-Between-Tests.html"/>
		<id>http://sebastian-bergmann.de/archives/884-guid.html</id>
		<updated>2010-02-14T09:40:10+00:00</updated>
		<content type="html">&lt;p&gt;There are few good reasons to share fixtures between tests, but in most cases the need to share a fixture between tests stems from an unresolved design problem.&lt;/p&gt;
&lt;p&gt;A good example of a fixture that makes sense to share across several tests is a database connection: you log into the database once and reuse the database connection instead of creating a new connection for each test. This makes your tests run faster.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.phpunit.de/&quot;&gt;PHPUnit 3.5&lt;/a&gt; removes the &lt;a href=&quot;http://www.phpunit.de/manual/3.4/en/fixtures.html#fixtures.sharing-fixture&quot;&gt;fixture sharing&lt;/a&gt; feature of the &lt;code&gt;TestSuite&lt;/code&gt; class. It was tedious to use this feature as it required the usage of a custom &lt;code&gt;TestSuite&lt;/code&gt; class in addition to the test case class. Furthermore, its implementation was a &quot;hack&quot;.&lt;/p&gt;
&lt;p&gt;PHPUnit 3.4 introduced the &lt;code&gt;setUpBeforeClass()&lt;/code&gt; and &lt;code&gt;tearDownAfterClass()&lt;/code&gt; template methods that can be used in a test case class. These methods allow a much cleaner and simpler implementation of fixture sharing between tests of the same test case class:&lt;/p&gt;
&lt;dl&gt;&lt;dd&gt;&lt;pre class=&quot;programlisting&quot;&gt;&lt;code&gt;&lt;span class=&quot;default&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;DatabaseTest&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;PHPUnit_Framework_TestCase&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;protected&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$dbh&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;setUpBeforeClass&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$dbh&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;PDO&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'sqlite::memory:'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;tearDownAfterClass&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$dbh&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/dd&gt;&lt;/dl&gt;
&lt;p&gt;The example above uses the &lt;code&gt;setUpBeforeClass()&lt;/code&gt; and &lt;code&gt;tearDownAfterClass()&lt;/code&gt; template methods to connect to the database before the test case class' first test and to disconnect from the database after the last test of the test case, respectively.&lt;/p&gt;
&lt;p&gt;It cannot be emphasized enough that &lt;a href=&quot;http://www.phpunit.de/manual/3.5/en/fixtures.html#fixtures.sharing-fixture&quot;&gt;sharing fixtures&lt;/a&gt; between tests reduces the value of the tests. The underlying design problem is that objects are not loosely coupled. You will achieve better results solving the underlying design problem and then writing tests using &lt;a href=&quot;http://www.phpunit.de/manual/current/en/test-doubles.html&quot;&gt;test doubles&lt;/a&gt;, than by creating dependencies between tests at runtime and ignoring the opportunity to improve your design.&lt;/p&gt;</content>
		<author>
			<name>Sebastian Bergmann</name>
			<email>nospam@example.com</email>
			<uri>http://sebastian-bergmann.de/</uri>
		</author>
		<source>
			<title type="html">Sebastian Bergmann - PHPUnit</title>
			<link rel="self" href="http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss"/>
			<id>http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss</id>
			<updated>2010-08-19T08:00:26+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Beurteilung von Frameworks anhand ihres Umganges mit Tests</title>
		<link href="http://test.ical.ly/2010/02/12/beurteilung-von-frameworks-anhand-ihres-umganges-mit-tests/"/>
		<id>http://test.ical.ly/?p=248</id>
		<updated>2010-02-12T06:30:21+00:00</updated>
		<content type="html">&lt;p&gt;Gestern wurde ich von einem Kollegen (danke Nils) auf das Blog &lt;a title=&quot;Whitewashing das Blog von Benjamin Eberlei&quot; href=&quot;http://www.whitewashing.de&quot; target=&quot;_blank&quot;&gt;whitewashing &lt;/a&gt;von Benjamin Eberlei aufmerksam gemacht. Benjamin ist ein aktiver Contributer verschiedener Open Source Projekte und hat viele interessante Posts geschrieben.&lt;/p&gt;
&lt;p&gt;An einem &lt;a title=&quot;Whitewashed - Speaking about Framework Quality on the IPC Spring 09&quot; href=&quot;http://www.whitewashing.de/blog/articles/113&quot; target=&quot;_blank&quot;&gt;Beitrag&lt;/a&gt; bin ich etwas h&#228;ngengeblieben. Er hat auf der IPCSpring im letzten Jahr einen Vortag &#252;ber Frameworks und ihren Umgang mit Tests gehalten. Man muss ein wenig googlen, um seine Slides zu finden, aber zu finden sind sie schliesslich &lt;a title=&quot;Slides zum Thema: Framework-Qualit&#228;t: Tests als G&#252;tesiegel &quot; href=&quot;http://www.slideshare.net/beberlei/frameworkqualitt-tests-als-gtesiegel&quot; target=&quot;_blank&quot;&gt;auf Slideshare&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Benjamin stellt das Zend Framwork, symfony, ezComponents und CakePHP gegen&#252;ber und beurteilt recht objektiv folgende Kriterien:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Einstellung des jeweiligen Projektes zum Thema Tests&lt;/li&gt;
&lt;li&gt;Anzahl der vorhandenen Unit Tests&lt;/li&gt;
&lt;li&gt;Eingesetztes Testing Framework&lt;/li&gt;
&lt;li&gt;Code Coverage&lt;/li&gt;
&lt;li&gt;Code Duplication&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Seine Ergebnisse sind nicht besonders &#252;berraschend. Oder doch?&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-248&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://test.ical.ly/wp-content/uploads/2010/02/subjektive-einschaetzung.jpg&quot;&gt;&lt;img class=&quot;aligncenter size-full wp-image-249&quot; title=&quot;subjektive-einschaetzung&quot; src=&quot;http://test.ical.ly/wp-content/uploads/2010/02/subjektive-einschaetzung.jpg&quot; alt=&quot;subjektive-einschaetzung&quot; width=&quot;510&quot; height=&quot;383&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Naja, vielleicht doch. Ich h&#228;tte durchaus erwartet, dass CakePHP das Schlusslicht bildet (ganz &#252;berheblich und ohne nennenswerte eigene Erfahrungen), auch erwartet h&#228;tte ich, dass symfony mit seinem eigenen Testing Framework lime und den (mitte letzten Jahres) nicht besonders zahlreichen Tests nicht viel besser da steht. Von den ezComponents h&#228;tte ich durchaus technische Brillianz erwartet, aber kein so gutes Abschneiden in Sachen Tests. Bisher hatte ich immer mal wieder mit ez Publish zu tun und da war zwar eine hohe Funktionalit&#228;t aber nicht nicht besonders hohe Qualit&#228;t zu erwarten (der ez Publish Code ist teilweise sehr Spaghetti-artig..). Zend h&#228;tte ich aber ganz klar ganz vorne erwartet.&lt;/p&gt;
&lt;p&gt;Als ich vor ein paar Tagen in meinen Code Coverage Versuchen zun&#228;chst den symfony Code mit analysiert hatte, war ich erstaunt &#252;ber die recht hohe Abdeckung. Ohne im Detail reingesehen zu haben, habe ich den Eindruck gehabt, als wenn mit der Entwicklung von symfony 1.4 deutlich mehr Wert auf Tests gelegt wurde. Vielleicht, aber das ist nur eine vorsichtige Hypothese, w&#252;rde symfony heute, ein paar Monate sp&#228;ter, besser da stehen.&lt;/p&gt;
&lt;p&gt;Aber Benjamin hat sicher Recht, wenn er sagt, es lohnt sich die Tests eines Frameworks zu betrachten, das man einsetzen m&#246;chte. Es sollte zumindest den eigenen Anspr&#252;chen gen&#252;gen, besser aber noch mehr als das. Eine gute Testabdeckung gibt auch dem Anwender eines Frameworks die Chance die Stabilit&#228;t von Releases zu beurteilen und gibt einen Anhaltspunkt, wie die eigenen Tests anzulegen sind. Im einfachsten Fall kann man immer etwas lernen.&lt;/p&gt;


&lt;!-- Begin SexyBookmarks Menu Code --&gt;
&lt;div class=&quot;sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-german&quot;&gt;
&lt;ul class=&quot;socials&quot;&gt;
		&lt;li class=&quot;sexy-twitter&quot;&gt;
			&lt;a href=&quot;http://twitter.com/home?status=Beurteilung+von+Frameworks+anhand+ihres+Umganges+mit+Tests+-+
&lt;html&gt;&lt;head&gt;
&lt;title&gt;301 Moved Permanently&lt;/title&gt;
&lt;/head&gt;&lt;body&gt;
&lt;h1&gt;Moved Permanently&lt;/h1&gt;
&lt;p&gt;The document has moved &lt;a href=&quot;&gt;
301 Moved Permanently

&lt;h1&gt;Moved Permanently&lt;/h1&gt;
&lt;p&gt;The document has moved &lt;a href=&quot;&gt;
301 Moved Permanently

&lt;h1&gt;Moved Permanently&lt;/h1&gt;
&lt;p&gt;The document has moved &lt;a href=&quot;&gt;
301 Moved Permanently

&lt;h1&gt;Moved Permanently&lt;/h1&gt;
&lt;p&gt;The document has moved &lt;a href=&quot;&gt;&lt;html&gt;&lt;head&gt;
&lt;title&gt;301 Moved Permanently&lt;/title&gt;
&lt;/head&gt;&lt;body&gt;
&lt;h1&gt;Moved Permanently&lt;/h1&gt;
&lt;p&gt;The document has moved &lt;a href=&quot;&gt;
301 Moved Permanently

&lt;h1&gt;Moved Permanently&lt;/h1&gt;
&lt;p&gt;The document has moved &lt;a href=&quot;&gt;
301 Moved Permanently

&lt;h1&gt;Moved Permanently&lt;/h1&gt;
&lt;p&gt;The document has moved &lt;a href=&quot;&gt;
301 Moved Permanently

&lt;h1&gt;Moved Permanently&lt;/h1&gt;
&lt;p&gt;The document has moved &lt;a href=&quot;http://www.shareaholic.com/pages/maintenanceapi.php?alias=&amp;url=http://test.ical.ly/2010/02/12/beurteilung-von-frameworks-anhand-ihres-umganges-mit-tests/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
+(via+@testically)&amp;amp;source=shareaholic&quot; rel=&quot;nofollow&quot; title=&quot;Twittere diesen Artikel!&quot;&gt;Twittere diesen Artikel!&lt;/a&gt;
		&lt;/p&gt;&lt;/a&gt;&lt;/p&gt;&lt;/a&gt;&lt;/p&gt;&lt;/a&gt;&lt;/li&gt;
		&lt;li class=&quot;sexy-delicious&quot;&gt;
			&lt;a href=&quot;http://delicious.com/post?url=http://test.ical.ly/2010/02/12/beurteilung-von-frameworks-anhand-ihres-umganges-mit-tests/&amp;title=Beurteilung+von+Frameworks+anhand+ihres+Umganges+mit+Tests&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei del.icio.us&quot;&gt;Empfehle diesen Artikel bei del.icio.us&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-reddit&quot;&gt;
			&lt;a href=&quot;http://reddit.com/submit?url=http://test.ical.ly/2010/02/12/beurteilung-von-frameworks-anhand-ihres-umganges-mit-tests/&amp;title=Beurteilung+von+Frameworks+anhand+ihres+Umganges+mit+Tests&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Reddit&quot;&gt;Empfehle diesen Artikel bei Reddit&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-stumbleupon&quot;&gt;
			&lt;a href=&quot;http://www.stumbleupon.com/submit?url=http://test.ical.ly/2010/02/12/beurteilung-von-frameworks-anhand-ihres-umganges-mit-tests/&amp;title=Beurteilung+von+Frameworks+anhand+ihres+Umganges+mit+Tests&quot; rel=&quot;nofollow&quot; title=&quot;Bei StumbleUpon einstellen&quot;&gt;Bei StumbleUpon einstellen&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-linkedin&quot;&gt;
			&lt;a href=&quot;http://www.linkedin.com/shareArticle?mini=true&amp;url=http://test.ical.ly/2010/02/12/beurteilung-von-frameworks-anhand-ihres-umganges-mit-tests/&amp;title=Beurteilung+von+Frameworks+anhand+ihres+Umganges+mit+Tests&amp;summary=Gestern%20wurde%20ich%20von%20einem%20Kollegen%20%28danke%20Nils%29%20auf%20das%20Blog%20whitewashing%20von%20Benjamin%20Eberlei%20aufmerksam%20gemacht.%20Benjamin%20ist%20ein%20aktiver%20Contributer%20verschiedener%20Open%20Source%20Projekte%20und%20hat%20viele%20interessante%20Posts%20geschrieben.%0D%0A%0D%0AAn%20einem%20Beitrag%20bin%20ich%20etwas%20h%C3%A4ngengeblieben.%20Er%20hat%20auf%20de&amp;source=test.ical.ly&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei LinkedIn&quot;&gt;Empfehle diesen Artikel bei LinkedIn&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-technorati&quot;&gt;
			&lt;a href=&quot;http://technorati.com/faves?add=http://test.ical.ly/2010/02/12/beurteilung-von-frameworks-anhand-ihres-umganges-mit-tests/&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Technorati&quot;&gt;Empfehle diesen Artikel bei Technorati&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-facebook&quot;&gt;
			&lt;a href=&quot;http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://test.ical.ly/2010/02/12/beurteilung-von-frameworks-anhand-ihres-umganges-mit-tests/&amp;t=Beurteilung+von+Frameworks+anhand+ihres+Umganges+mit+Tests&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Facebook&quot;&gt;Empfehle diesen Artikel bei Facebook&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-google&quot;&gt;
			&lt;a href=&quot;http://test.ical.ly/2010/02/12/beurteilung-von-frameworks-anhand-ihres-umganges-mit-tests/&quot; rel=&quot;nofollow&quot; title=&quot;&quot;&gt;&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-misterwong&quot;&gt;
			&lt;a href=&quot;http://www.mister-wong.de/addurl/?bm_url=http://test.ical.ly/2010/02/12/beurteilung-von-frameworks-anhand-ihres-umganges-mit-tests/&amp;bm_description=Beurteilung+von+Frameworks+anhand+ihres+Umganges+mit+Tests&amp;plugin=sexybookmarks&quot; rel=&quot;nofollow&quot; title=&quot;F&#252;ge hinzu zu Mister Wong&quot;&gt;F&#252;ge hinzu zu Mister Wong&lt;/a&gt;
		&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;!-- End SexyBookmarks Menu Code --&gt;</content>
		<author>
			<name>Christian</name>
			<uri>http://test.ical.ly</uri>
		</author>
		<source>
			<title type="html">test.ical.ly &#187; phpUnit</title>
			<subtitle type="html">getting PHP by the balls</subtitle>
			<link rel="self" href="http://test.ical.ly/tags/phpunit/feed/atom/"/>
			<id>http://test.ical.ly/feed/atom/</id>
			<updated>2010-09-01T00:00:27+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Stubbing and Mocking Static Methods</title>
		<link href="http://sebastian-bergmann.de/archives/883-Stubbing-and-Mocking-Static-Methods.html"/>
		<id>http://sebastian-bergmann.de/archives/883-guid.html</id>
		<updated>2010-02-12T05:30:00+00:00</updated>
		<content type="html">&lt;p&gt;&lt;strong&gt;This article is part of a series on testing untestable code:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://sebastian-bergmann.de/archives/881-Testing-Your-Privates.html&quot;&gt;Testing private methods&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sebastian-bergmann.de/archives/882-Testing-Code-That-Uses-Singletons.html&quot;&gt;Testing code that uses singletons&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sebastian-bergmann.de/archives/883-Stubbing-and-Mocking-Static-Methods.html&quot;&gt;Stubbing static methods&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sebastian-bergmann.de/archives/885-Stubbing-Hard-Coded-Dependencies.html&quot;&gt;Stubbing hard-coded dependencies&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/p&gt;
&lt;p&gt;With PHPUnit 3.5 it will be possible to stub and mock static methods.&lt;/p&gt;
&lt;p&gt;Consider the class &lt;code&gt;Foo&lt;/code&gt;:&lt;/p&gt;

&lt;dl&gt;&lt;dd&gt;&lt;pre class=&quot;programlisting&quot;&gt;&lt;code&gt;&lt;span class=&quot;default&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Foo&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;helper&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;helper&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'foo'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/dd&gt;&lt;/dl&gt;

&lt;p&gt;When testing &lt;code&gt;Foo::doSomething()&lt;/code&gt; we want to decouple it from its dependency &lt;code&gt;Foo::helper()&lt;/code&gt;. With PHPUnit 3.5 and PHP 5.3 as well as consistent use of late static binding (using &lt;code&gt;static::&lt;/code&gt; instead of &lt;code&gt;self::&lt;/code&gt;) the following is possible:&lt;/p&gt;

&lt;dl&gt;&lt;dd&gt;&lt;pre class=&quot;programlisting&quot;&gt;&lt;code&gt;&lt;span class=&quot;default&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;FooTest&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;PHPUnit_Framework_TestCase&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;testDoSomething&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$class&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;getMockClass&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'Foo'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;/*&amp;#160;name&amp;#160;of&amp;#160;class&amp;#160;to&amp;#160;mock&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;*/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'helper'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;/*&amp;#160;list&amp;#160;of&amp;#160;methods&amp;#160;to&amp;#160;mock&amp;#160;&amp;#160;&amp;#160;*/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$class&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;staticExpects&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'helper'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;will&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;returnValue&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'bar'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;assertEquals&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'bar'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$class&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/dd&gt;&lt;/dl&gt;

&lt;p&gt;The new &lt;code&gt;staticExpects()&lt;/code&gt; method works similar to the non-static &lt;code&gt;expects()&lt;/code&gt; variant.&lt;/p&gt;

&lt;p&gt;This approach only works for the stubbing and mocking of static method calls where &lt;em&gt;caller&lt;/em&gt; and &lt;em&gt;callee&lt;/em&gt; are in the same class. This is because &lt;a href=&quot;http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/&quot;&gt;static methods are death to testability&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;&quot;&lt;em&gt;Unit-Testing needs seams, seams is where we prevent the execution of normal code path and is how we achieve isolation of the class under test. Seams work through polymorphism, we override/implement class/interface and then wire the class under test differently in order to take control of the execution flow. With static methods there is nothing to override. Yes, static methods are easy to call, but if the static method calls another static method there is no way to override the called method dependency.&lt;/em&gt;&quot;&lt;/blockquote&gt;</content>
		<author>
			<name>Sebastian Bergmann</name>
			<email>nospam@example.com</email>
			<uri>http://sebastian-bergmann.de/</uri>
		</author>
		<source>
			<title type="html">Sebastian Bergmann - PHPUnit</title>
			<link rel="self" href="http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss"/>
			<id>http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss</id>
			<updated>2010-08-19T08:00:26+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Testing Code That Uses Singletons</title>
		<link href="http://sebastian-bergmann.de/archives/882-Testing-Code-That-Uses-Singletons.html"/>
		<id>http://sebastian-bergmann.de/archives/882-guid.html</id>
		<updated>2010-02-11T14:45:00+00:00</updated>
		<content type="html">&lt;p&gt;&lt;strong&gt;This article is part of a series on testing untestable code:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://sebastian-bergmann.de/archives/881-Testing-Your-Privates.html&quot;&gt;Testing private methods&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sebastian-bergmann.de/archives/882-Testing-Code-That-Uses-Singletons.html&quot;&gt;Testing code that uses singletons&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sebastian-bergmann.de/archives/883-Stubbing-and-Mocking-Static-Methods.html&quot;&gt;Stubbing static methods&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sebastian-bergmann.de/archives/885-Stubbing-Hard-Coded-Dependencies.html&quot;&gt;Stubbing hard-coded dependencies&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/p&gt;
&lt;p&gt;I frequently quote &lt;a href=&quot;http://misko.hevery.com/&quot;&gt;Mi&#353;ko Hevery&lt;/a&gt; with&lt;/p&gt;
&lt;blockquote&gt;&quot;&lt;em&gt;&lt;a href=&quot;http://googletesting.blogspot.com/2008/05/tott-using-dependancy-injection-to.html&quot;&gt;It is hard to test code that uses singletons.&lt;/a&gt;&lt;/em&gt;&quot;&lt;/blockquote&gt;
&lt;p&gt;And then my audience asks me ...&lt;/p&gt;
&lt;h4&gt;Why is it hard to test code that uses singletons?&lt;/h4&gt;
&lt;p&gt;Lets have a look at the default implementation of the &lt;a href=&quot;http://en.wikipedia.org/wiki/Singleton_pattern&quot;&gt;Singleton&lt;/a&gt; design pattern in PHP:&lt;/p&gt;
&lt;dl&gt;&lt;dd&gt;&lt;pre class=&quot;programlisting&quot;&gt;&lt;code&gt;&lt;span class=&quot;default&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Singleton&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$uniqueInstance&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;protected&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;__construct&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;final&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;__clone&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;getInstance&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$uniqueInstance&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;===&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$uniqueInstance&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Singleton&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$uniqueInstance&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/dd&gt;&lt;/dl&gt;
&lt;p&gt;The code above declares a class that cannot be instantiated (or cloned) by a client using the &lt;code&gt;new&lt;/code&gt; (or &lt;code&gt;clone&lt;/code&gt;) operator(s). To get a reference to the only instance of the class one has to use the static method &lt;code&gt;getInstance()&lt;/code&gt;. Usually the code that uses the Singleton (which we will refer to as &lt;em&gt;client&lt;/em&gt;) is strongly coupled to the &lt;code&gt;getInstance()&lt;/code&gt; method:&lt;/p&gt;
&lt;dl&gt;&lt;dd&gt;&lt;pre class=&quot;programlisting&quot;&gt;&lt;code&gt;&lt;span class=&quot;default&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Client&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$singleton&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Singleton&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;getInstance&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;//&amp;#160;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/dd&gt;&lt;/dl&gt;
&lt;p&gt;It is impossible to write a test for the &lt;code&gt;doSomething()&lt;/code&gt; method without also invoking the singleton's &lt;code&gt;getInstance()&lt;/code&gt; method. This means that we cannot get a fresh instance of the &lt;code&gt;Singleton&lt;/code&gt; class and thus have no guarantee that there are no side effects in multiple tests that interact with the singleton.&lt;/p&gt;
&lt;h4&gt;Dependency Injection&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Dependency_Injection&quot;&gt;Dependency Injection&lt;/a&gt; can help with decoupling the client from the &lt;code&gt;getInstance()&lt;/code&gt; method:&lt;/p&gt;
&lt;dl&gt;&lt;dd&gt;&lt;pre class=&quot;programlisting&quot;&gt;&lt;code&gt;&lt;span class=&quot;default&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Client&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Singleton&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$singleton&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$singleton&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;===&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$singleton&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Singleton&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;getInstance&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;//&amp;#160;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/dd&gt;&lt;/dl&gt;
&lt;p&gt;Instead of unconditionally invoking the &lt;code&gt;getInstance()&lt;/code&gt; method inside the &lt;code&gt;doSomething()&lt;/code&gt; we can now optionally pass in an instance of the &lt;code&gt;Singleton&lt;/code&gt; class. This allows us to pass in a &lt;em&gt;test-specific equivalent&lt;/em&gt; such as a &lt;em&gt;mock object&lt;/em&gt; or &lt;em&gt;stub&lt;/em&gt;:&lt;/p&gt;
&lt;dl&gt;&lt;dd&gt;&lt;pre class=&quot;programlisting&quot;&gt;&lt;code&gt;&lt;span class=&quot;default&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;ClientTest&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;PHPUnit_Framework_TestCase&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;testSingleton&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$singleton&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;getMock&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'Singleton'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;/*&amp;#160;name&amp;#160;of&amp;#160;class&amp;#160;to&amp;#160;mock&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;*/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;/*&amp;#160;list&amp;#160;of&amp;#160;methods&amp;#160;to&amp;#160;mock&amp;#160;&amp;#160;&amp;#160;*/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;/*&amp;#160;constructor&amp;#160;arguments&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;*/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;/*&amp;#160;name&amp;#160;for&amp;#160;mocked&amp;#160;class&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;*/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;FALSE&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;/*&amp;#160;do&amp;#160;not&amp;#160;invoke&amp;#160;constructor&amp;#160;*/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;//&amp;#160;...&amp;#160;configure&amp;#160;$singleton&amp;#160;...&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$client&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Client&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$client&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$singleton&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;//&amp;#160;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/dd&gt;&lt;/dl&gt;
&lt;h4&gt;Alternative Singleton Implementations&lt;/h4&gt;
&lt;p&gt;Either as an alternative or in addition to rewriting the clients to optionally accept an instance of the &lt;code&gt;Singleton&lt;/code&gt; class as an argument, we can also rewrite the &lt;code&gt;Singleton&lt;/code&gt; class to make testing easier.&lt;/p&gt;
&lt;h5&gt;Resettable Singleton&lt;/h5&gt;
&lt;p&gt;The first approach is to add a &lt;code&gt;reset()&lt;/code&gt; method to the &lt;code&gt;Singleton&lt;/code&gt; class:&lt;/p&gt;
&lt;dl&gt;&lt;dd&gt;&lt;pre class=&quot;programlisting&quot;&gt;&lt;code&gt;&lt;span class=&quot;default&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Singleton&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$uniqueInstance&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;protected&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;__construct&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;final&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;__clone&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;getInstance&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$uniqueInstance&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;===&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$uniqueInstance&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Singleton&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$uniqueInstance&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;reset&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$uniqueInstance&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/dd&gt;&lt;/dl&gt;
&lt;p&gt;Invoking the &lt;code&gt;reset()&lt;/code&gt; method causes the &lt;code&gt;getInstance()&lt;/code&gt; method to create a fresh object of the &lt;code&gt;Singleton&lt;/code&gt; class the next time it is called.&lt;/p&gt;
&lt;h5&gt;Singleton with Test Context&lt;/h5&gt;
&lt;p&gt;The second approach is to add a &lt;em&gt;testing context&lt;/em&gt; to the &lt;code&gt;Singleton&lt;/code&gt; class:&lt;/p&gt;
&lt;dl&gt;&lt;dd&gt;&lt;pre class=&quot;programlisting&quot;&gt;&lt;code&gt;&lt;span class=&quot;default&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Singleton&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$uniqueInstance&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$testing&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;FALSE&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;protected&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;__construct&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;final&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;__clone&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;getInstance&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$uniqueInstance&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;===&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;||&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$testing&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$uniqueInstance&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Singleton&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$uniqueInstance&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/dd&gt;&lt;/dl&gt;
&lt;p&gt;Setting &lt;code&gt;Singleton::$testing = TRUE;&lt;/code&gt; causes the &lt;code&gt;getInstance()&lt;/code&gt; method to create a fresh object of the &lt;code&gt;Singleton&lt;/code&gt; class each time it is called.&lt;/p&gt;
&lt;h4&gt;PHPUnit Can Help, Too&lt;/h4&gt;
&lt;p&gt;PHPUnit has a &lt;a href=&quot;http://www.phpunit.de/manual/current/en/fixtures.html#fixtures.global-state&quot;&gt;backup/restore mechanism for static attributes of classes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is yet another feature of PHPUnit that makes the testing of code that uses global state (which includes, but is not limited to, &lt;a href=&quot;http://sebastian-bergmann.de/archives/797-Global-Variables-and-PHPUnit.html&quot;&gt;global and superglobal variables&lt;/a&gt; as well as static attributes of classes) easier.&lt;/p&gt;
&lt;h4&gt;Just Because You Can, Does Not Mean You Should&lt;/h4&gt;
&lt;p&gt;Yes, it is possible write testable code that uses singletons.&lt;br /&gt;This does not mean, however, that you should use them without thinking twice.&lt;/p&gt;</content>
		<author>
			<name>Sebastian Bergmann</name>
			<email>nospam@example.com</email>
			<uri>http://sebastian-bergmann.de/</uri>
		</author>
		<source>
			<title type="html">Sebastian Bergmann - PHPUnit</title>
			<link rel="self" href="http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss"/>
			<id>http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss</id>
			<updated>2010-08-19T08:00:26+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Undokumentierte Details der PHPUnit Konfigurations XML Datei</title>
		<link href="http://test.ical.ly/2010/02/11/undokumentierte-details-der-phpunit-konfigurations-xml-datei/"/>
		<id>http://test.ical.ly/?p=239</id>
		<updated>2010-02-11T09:52:00+00:00</updated>
		<content type="html">&lt;p&gt;Ich spiele immer noch mit meiner phpunit.xml Konfigurations Datei rum. Irgendwie bin ich immer noch nicht zufrieden, immer wieder google ich nach mehr Informationen. Aber ich will heute gar nicht gross darauf eingehen, was mir an meiner Konfiguration nicht passt, sondern auf zwei Details aufmerksam machen, die nicht dokumentiert sind (afaik) und die in Netz entweder so gut wie garnicht  zu erfahren sind bzw. oftmals falsch beschrieben werden.&lt;/p&gt;
&lt;p&gt;Hier nochmal der &lt;a title=&quot;PHPUnit 3.4 english - Appendix C. The XML Configuration File &quot; href=&quot;http://www.phpunit.de/manual/current/en/appendixes.configuration.html&quot; target=&quot;_blank&quot;&gt;Link zur offiziellen Dokumentation&lt;/a&gt; dieser Datei.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.phpunit.de/manual/phpunit-logo.gif&quot; alt=&quot;PHPUnit&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Und hier die drei inoffiziellen Nachtr&#228;ge dazu:&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-239&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;Relative Pfadangaben in der phpunit.xml&lt;/h3&gt;
&lt;p&gt;In der PHPUnit XML Konfiguration kann man eine Menge Pfade angeben. Ich halte das oft f&#252;r redundant, aber das soll nicht das Problem sein.&lt;/p&gt;
&lt;p&gt;Wenn man aber versucht zu erfahren, worauf sich relative angegebene Pfade beziehen, wie z.B. &lt;em&gt;./test/AllTests.php&lt;/em&gt; dann findet man in der offiziellen Dokumentation nichts dar&#252;ber. In vielen Foren und Blogs findet man wiederum viele Aussagen. Die meisten sind Fragen aber die wenigen Antworten sind zum gr&#246;&#223;tenteil falsch, oder zumindest nicht richtig. Die Aussage findet sich h&#228;ufig, &lt;em&gt;dass relative Pfad Angaben in der PHPUnit Konfiguration relativ zur XML Datei sind&lt;/em&gt;. F&#252;hrt man PHPUnit dort aus, wo sich diese Datei befindet stimmt das auch:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;sh&quot;&gt;$ phpunit --configuration=phpunit.xml ..&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;F&#252;hrt man aber PHPUnit an einem anderen Ort als dem der XML Datei aus, z.B.:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;sh&quot;&gt;$ phpunit --configuration=pfad/zu/meiner/phpunit.xml ..&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Dann stimmt das nicht mehr.&lt;/p&gt;
&lt;p&gt;Der Grund: &lt;strong&gt;Pfadangaben in der PHPUnit Konfigurations XML Datei sind immer relativ zum Verzeichnis, in dem der &lt;em&gt;&lt;span&gt;phpunit&lt;/span&gt;&lt;/em&gt; Befehl abgegeben wird!&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;PHPUnit Coverage Reporte beachten einige Dateien nicht&lt;/h3&gt;
&lt;p&gt;&#220;ber diese Information bin ich eher zuf&#228;llig und nur an einer Stelle gestolpert n&#228;mlich&#160;&lt;a title=&quot;Axel Jungs Blog&quot; href=&quot;http://www.ajung.de/2010/01/28/bessere-coverage-analyse-mit-adduncoveredfilesfromwhitelist/&quot; target=&quot;_blank&quot;&gt;hier&lt;/a&gt;. Danke Axel!&lt;/p&gt;
&lt;p&gt;Der normale Coverage Report Erstellung Mechanismus (tolles Wort!) von PHPUnit betrachtet alle Dateien, die von einem deiner Tests &amp;#8220;angefasst&amp;#8221; wurden.&lt;/p&gt;
&lt;p&gt;Hast du eine Datei vergessen zu testen, taucht sie so nicht unbedingt im Report auf. Das kann ich dann mit &lt;em&gt;&lt;strong&gt;addUncoveredFilesFromWhitelist&lt;/strong&gt;&lt;/em&gt;&lt;em&gt; &lt;/em&gt;umgehen.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;xml&quot;&gt;...
&lt;span&gt;&lt;span&gt;&amp;lt;filter&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
...
  &lt;span&gt;&lt;span&gt;&amp;lt;whitelist&lt;/span&gt; &lt;span&gt;addUncoveredFilesFromWhitelist&lt;/span&gt;=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;directory&lt;/span&gt; &lt;span&gt;suffix&lt;/span&gt;=&lt;span&gt;&amp;quot;.php&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;../domain&lt;span&gt;&lt;span&gt;&amp;lt;/directory&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span&gt;&lt;span&gt;&amp;lt;directory&lt;/span&gt; &lt;span&gt;suffix&lt;/span&gt;=&lt;span&gt;&amp;quot;.php&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;../system&lt;span&gt;&lt;span&gt;&amp;lt;/directory&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
      ...
  &lt;span&gt;&lt;span&gt;&amp;lt;/whitelist&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
...
&lt;span&gt;&lt;span&gt;&amp;lt;/filter&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
...&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Prima Feature, nur leider undokumentiert.. Googled man nach dem Begriff findet man neben Axels Blog nicht viel, allerdings findet sich eine der Sourcen von PHPUnit und darin ein &lt;a title=&quot;Quellen von PHPUnit/Util/Configuration.php&quot; href=&quot;http://github.com/sebastianbergmann/phpunit/blob/e2f284f0179c7894e18033b65e6faeda6e7478f0/PHPUnit/Util/Configuration.php&quot; target=&quot;_blank&quot;&gt;Beispiel XML in den DocBlocks&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;In der PHPUnit Konfiguration den PHP Include Path setzen&lt;/h3&gt;
&lt;p&gt;Sich die Quellen von PHPUnit anzusehen, bringt weiteres zum Vorschein. So ist es neben den dokumentierten M&#246;glichkeiten ini Settings, Konstanten und globale Variablen zu setzen auch m&#246;glich den Includepfad von PHP zu setzen.&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;xml&quot;&gt;...
&lt;span&gt;&lt;span&gt;&amp;lt;php&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;includePath&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;span&gt;&lt;span&gt;&amp;lt;/includePath&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;ini&lt;/span&gt; &lt;span&gt;name&lt;/span&gt;=&lt;span&gt;&amp;quot;foo&amp;quot;&lt;/span&gt; &lt;span&gt;value&lt;/span&gt;=&lt;span&gt;&amp;quot;bar&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;const&lt;/span&gt; &lt;span&gt;name&lt;/span&gt;=&lt;span&gt;&amp;quot;foo&amp;quot;&lt;/span&gt; &lt;span&gt;value&lt;/span&gt;=&lt;span&gt;&amp;quot;bar&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span&gt;&lt;span&gt;&amp;lt;var&lt;/span&gt; &lt;span&gt;name&lt;/span&gt;=&lt;span&gt;&amp;quot;foo&amp;quot;&lt;/span&gt; &lt;span&gt;value&lt;/span&gt;=&lt;span&gt;&amp;quot;bar&amp;quot;&lt;/span&gt;&lt;span&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
  ...
&lt;span&gt;&lt;span&gt;&amp;lt;/php&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
...&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ich hab dieses Feature aber noch nicht selbst ausprobiert und kann nicht sagen, ob es den angegebenen Pfad hinzuf&#252;gt (w&#252;rde ich erwarten) oder ob es alle Includepfade &#252;berschreibt.&lt;/p&gt;
&lt;p&gt;Versteht mich bitte nicht falsch, die Dokumentation von PHPUnit ist super umfangreich und informativ. Nur einige wenige Details fehlen, die vielleicht dem ein oder anderen weitrerhelfen, wenn er sie hier findet.&lt;/p&gt;


&lt;!-- Begin SexyBookmarks Menu Code --&gt;
&lt;div class=&quot;sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-german&quot;&gt;
&lt;ul class=&quot;socials&quot;&gt;
		&lt;li class=&quot;sexy-twitter&quot;&gt;
			&lt;a href=&quot;http://twitter.com/home?status=Undokumentierte+Details+der+PHPUnit+Konfigurations+XML+Datei+-+
&lt;html&gt;&lt;head&gt;
&lt;title&gt;301 Moved Permanently&lt;/title&gt;
&lt;/head&gt;&lt;body&gt;
&lt;h1&gt;Moved Permanently&lt;/h1&gt;
&lt;p&gt;The document has moved &lt;a href=&quot;&gt;
301 Moved Permanently

&lt;h1&gt;Moved Permanently&lt;/h1&gt;
&lt;p&gt;The document has moved &lt;a href=&quot;&gt;
301 Moved Permanently

&lt;h1&gt;Moved Permanently&lt;/h1&gt;
&lt;p&gt;The document has moved &lt;a href=&quot;&gt;
301 Moved Permanently

&lt;h1&gt;Moved Permanently&lt;/h1&gt;
&lt;p&gt;The document has moved &lt;a href=&quot;&gt;&lt;html&gt;&lt;head&gt;
&lt;title&gt;301 Moved Permanently&lt;/title&gt;
&lt;/head&gt;&lt;body&gt;
&lt;h1&gt;Moved Permanently&lt;/h1&gt;
&lt;p&gt;The document has moved &lt;a href=&quot;&gt;
301 Moved Permanently

&lt;h1&gt;Moved Permanently&lt;/h1&gt;
&lt;p&gt;The document has moved &lt;a href=&quot;&gt;
301 Moved Permanently

&lt;h1&gt;Moved Permanently&lt;/h1&gt;
&lt;p&gt;The document has moved &lt;a href=&quot;&gt;
301 Moved Permanently

&lt;h1&gt;Moved Permanently&lt;/h1&gt;
&lt;p&gt;The document has moved &lt;a href=&quot;http://www.shareaholic.com/pages/maintenanceapi.php?alias=&amp;url=http://test.ical.ly/2010/02/11/undokumentierte-details-der-phpunit-konfigurations-xml-datei/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
+(via+@testically)&amp;amp;source=shareaholic&quot; rel=&quot;nofollow&quot; title=&quot;Twittere diesen Artikel!&quot;&gt;Twittere diesen Artikel!&lt;/a&gt;
		&lt;/p&gt;&lt;/a&gt;&lt;/p&gt;&lt;/a&gt;&lt;/p&gt;&lt;/a&gt;&lt;/li&gt;
		&lt;li class=&quot;sexy-delicious&quot;&gt;
			&lt;a href=&quot;http://delicious.com/post?url=http://test.ical.ly/2010/02/11/undokumentierte-details-der-phpunit-konfigurations-xml-datei/&amp;title=Undokumentierte+Details+der+PHPUnit+Konfigurations+XML+Datei&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei del.icio.us&quot;&gt;Empfehle diesen Artikel bei del.icio.us&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-reddit&quot;&gt;
			&lt;a href=&quot;http://reddit.com/submit?url=http://test.ical.ly/2010/02/11/undokumentierte-details-der-phpunit-konfigurations-xml-datei/&amp;title=Undokumentierte+Details+der+PHPUnit+Konfigurations+XML+Datei&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Reddit&quot;&gt;Empfehle diesen Artikel bei Reddit&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-stumbleupon&quot;&gt;
			&lt;a href=&quot;http://www.stumbleupon.com/submit?url=http://test.ical.ly/2010/02/11/undokumentierte-details-der-phpunit-konfigurations-xml-datei/&amp;title=Undokumentierte+Details+der+PHPUnit+Konfigurations+XML+Datei&quot; rel=&quot;nofollow&quot; title=&quot;Bei StumbleUpon einstellen&quot;&gt;Bei StumbleUpon einstellen&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-linkedin&quot;&gt;
			&lt;a href=&quot;http://www.linkedin.com/shareArticle?mini=true&amp;url=http://test.ical.ly/2010/02/11/undokumentierte-details-der-phpunit-konfigurations-xml-datei/&amp;title=Undokumentierte+Details+der+PHPUnit+Konfigurations+XML+Datei&amp;summary=Ich%20spiele%20immer%20noch%20mit%20meiner%20phpunit.xml%20Konfigurations%20Datei%20rum.%20Irgendwie%20bin%20ich%20immer%20noch%20nicht%20zufrieden%2C%20immer%20wieder%20google%20ich%20nach%20mehr%20Informationen.%20Aber%20ich%20will%20heute%20gar%20nicht%20gross%20darauf%20eingehen%2C%20was%20mir%20an%20meiner%20Konfiguration%20nicht%20passt%2C%20sondern%20auf%20zwei%20Details%20aufmerksam%20&amp;source=test.ical.ly&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei LinkedIn&quot;&gt;Empfehle diesen Artikel bei LinkedIn&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-technorati&quot;&gt;
			&lt;a href=&quot;http://technorati.com/faves?add=http://test.ical.ly/2010/02/11/undokumentierte-details-der-phpunit-konfigurations-xml-datei/&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Technorati&quot;&gt;Empfehle diesen Artikel bei Technorati&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-facebook&quot;&gt;
			&lt;a href=&quot;http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://test.ical.ly/2010/02/11/undokumentierte-details-der-phpunit-konfigurations-xml-datei/&amp;t=Undokumentierte+Details+der+PHPUnit+Konfigurations+XML+Datei&quot; rel=&quot;nofollow&quot; title=&quot;Empfehle diesen Artikel bei Facebook&quot;&gt;Empfehle diesen Artikel bei Facebook&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-google&quot;&gt;
			&lt;a href=&quot;http://test.ical.ly/2010/02/11/undokumentierte-details-der-phpunit-konfigurations-xml-datei/&quot; rel=&quot;nofollow&quot; title=&quot;&quot;&gt;&lt;/a&gt;
		&lt;/li&gt;
		&lt;li class=&quot;sexy-misterwong&quot;&gt;
			&lt;a href=&quot;http://www.mister-wong.de/addurl/?bm_url=http://test.ical.ly/2010/02/11/undokumentierte-details-der-phpunit-konfigurations-xml-datei/&amp;bm_description=Undokumentierte+Details+der+PHPUnit+Konfigurations+XML+Datei&amp;plugin=sexybookmarks&quot; rel=&quot;nofollow&quot; title=&quot;F&#252;ge hinzu zu Mister Wong&quot;&gt;F&#252;ge hinzu zu Mister Wong&lt;/a&gt;
		&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;!-- End SexyBookmarks Menu Code --&gt;</content>
		<author>
			<name>Christian</name>
			<uri>http://test.ical.ly</uri>
		</author>
		<source>
			<title type="html">test.ical.ly &#187; phpUnit</title>
			<subtitle type="html">getting PHP by the balls</subtitle>
			<link rel="self" href="http://test.ical.ly/tags/phpunit/feed/atom/"/>
			<id>http://test.ical.ly/feed/atom/</id>
			<updated>2010-09-01T00:00:27+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">Testing Your Privates</title>
		<link href="http://sebastian-bergmann.de/archives/881-Testing-Your-Privates.html"/>
		<id>http://sebastian-bergmann.de/archives/881-guid.html</id>
		<updated>2010-02-09T12:00:59+00:00</updated>
		<content type="html">&lt;p&gt;&lt;strong&gt;This article is part of a series on testing untestable code:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://sebastian-bergmann.de/archives/881-Testing-Your-Privates.html&quot;&gt;Testing private methods&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sebastian-bergmann.de/archives/882-Testing-Code-That-Uses-Singletons.html&quot;&gt;Testing code that uses singletons&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sebastian-bergmann.de/archives/883-Stubbing-and-Mocking-Static-Methods.html&quot;&gt;Stubbing static methods&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sebastian-bergmann.de/archives/885-Stubbing-Hard-Coded-Dependencies.html&quot;&gt;Stubbing hard-coded dependencies&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/p&gt;
&lt;p&gt;No, not &lt;a href=&quot;http://en.wikipedia.org/wiki/Sex_organ&quot;&gt;those privates&lt;/a&gt;. If you need help with those, &lt;a href=&quot;http://oreilly.com/catalog/9780596801755/&quot;&gt;this book&lt;/a&gt; might help.&lt;/p&gt;
&lt;p&gt;One question I get over and over again when talking about &lt;a href=&quot;http://en.wikipedia.org/wiki/Unit_Testing&quot;&gt;Unit Testing&lt;/a&gt; is this:&lt;/p&gt;
&lt;blockquote&gt;&quot;&lt;em&gt;How do I test the private attributes and methods of my objects?&lt;/em&gt;&quot;&lt;/blockquote&gt;
&lt;p&gt;Lets assume we have a class &lt;code&gt;Foo&lt;/code&gt;:
&lt;dl&gt;&lt;dd&gt;&lt;pre class=&quot;programlisting&quot;&gt;&lt;code&gt;&lt;span class=&quot;default&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Foo&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$bar&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'baz'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;doSomethingPrivate&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;doSomethingPrivate&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'blah'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/dd&gt;&lt;/dl&gt;
&lt;p&gt;Before we explore how &lt;code&gt;protected&lt;/code&gt; and &lt;code&gt;private&lt;/code&gt; attributes and methods can be tested directly, lets have a look at how they can be tested indirectly.&lt;/p&gt;
&lt;p&gt;The following test calls the &lt;code&gt;testDoSomething()&lt;/code&gt; method which in turn calls the &lt;code&gt;doSomethingPrivate()&lt;/code&gt; method:&lt;/p&gt;
&lt;dl&gt;&lt;dd&gt;&lt;pre class=&quot;programlisting&quot;&gt;&lt;code&gt;&lt;span class=&quot;default&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;FooTest&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;PHPUnit_Framework_TestCase&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;/**&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;*&amp;#160;@covers&amp;#160;Foo::doSomething&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;*&amp;#160;@covers&amp;#160;Foo::doSomethingPrivate&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;*/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;testDoSomething&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$foo&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;assertEquals&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'blah'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$foo&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/dd&gt;&lt;/dl&gt;
&lt;p&gt;The test above assumes that &lt;code&gt;testDoSomething()&lt;/code&gt; only works correctly when &lt;code&gt;testDoSomethingPrivate()&lt;/code&gt; works correctly. This means that we have indirectly tested &lt;code&gt;testDoSomethingPrivate()&lt;/code&gt;. The problem with this approach is that when the test fails we do not know directly where the root cause for the failure is. It could be in either &lt;code&gt;testDoSomething()&lt;/code&gt; or &lt;code&gt;testDoSomethingPrivate()&lt;/code&gt;. This makes the test less valuable.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.phpunit.de/&quot;&gt;PHPUnit&lt;/a&gt; supports reading &lt;code&gt;protected&lt;/code&gt; and &lt;code&gt;private&lt;/code&gt; attributes through the &lt;code&gt;PHPUnit_Framework_Assert::readAttribute()&lt;/code&gt; method. Convenience wrappers such as &lt;code&gt;PHPUnit_Framework_TestCase::assertAttributeEquals()&lt;/code&gt; exist to express assertions on &lt;code&gt;protected&lt;/code&gt; and &lt;code&gt;private&lt;/code&gt; attributes:&lt;/p&gt;
&lt;dl&gt;&lt;dd&gt;&lt;pre class=&quot;programlisting&quot;&gt;&lt;code&gt;&lt;span class=&quot;default&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;FooTest&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;PHPUnit_Framework_TestCase&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;testPrivateAttribute&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;assertAttributeEquals&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'baz'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;/*&amp;#160;expected&amp;#160;value&amp;#160;*/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'bar'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;/*&amp;#160;attribute&amp;#160;name&amp;#160;*/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;/*&amp;#160;object&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;*/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/dd&gt;&lt;/dl&gt;
&lt;p&gt;PHP 5.3.2 introduces the &lt;code&gt;ReflectionMethod::setAccessible()&lt;/code&gt; method to allow the invocation of &lt;code&gt;protected&lt;/code&gt; and &lt;code&gt;private&lt;/code&gt; methods through the Reflection API:&lt;/p&gt;
&lt;dl&gt;&lt;dd&gt;&lt;pre class=&quot;programlisting&quot;&gt;&lt;code&gt;&lt;span class=&quot;default&quot;&gt;&amp;lt;?php&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;FooTest&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;PHPUnit_Framework_TestCase&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;/**&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;*&amp;#160;@covers&amp;#160;Foo::doSomethingPrivate&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;comment&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;*/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;testPrivateMethod&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$method&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;ReflectionMethod&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'Foo'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'doSomethingPrivate'&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$method&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;setAccessible&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;TRUE&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&amp;#160;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;assertEquals&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;'blah'&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;$method&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;invoke&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&lt;/span&gt;&lt;span class=&quot;default&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;/span&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;default&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/dd&gt;&lt;/dl&gt;
&lt;p&gt;In the test above we directly test &lt;code&gt;testDoSomethingPrivate()&lt;/code&gt;. When it fails we immediately know where to look for the root cause.&lt;/p&gt;
&lt;p&gt;I agree with Dave Thomas and Andy Hunt, who write in their book &quot;Pragmatic Unit Testing&quot;:&lt;/p&gt;
&lt;blockquote&gt;&quot;&lt;em&gt;In general, you don't want to break any encapsulation for the sake of testing (or as Mom used to say, &quot;don't expose your privates!&quot;). Most of the time, you should be able to test a class by exercising its public methods. If there is significant functionality that is hidden behind private or protected access, that might be a warning sign that there's another class in there struggling to get out.&lt;/em&gt;&quot;&lt;/blockquote&gt;
&lt;p&gt;So: Just because the testing of &lt;code&gt;protected&lt;/code&gt; and &lt;code&gt;private&lt;/code&gt; attributes and methods is possible does not mean that this is a &quot;good thing&quot;.&lt;/p&gt;&lt;/p&gt;</content>
		<author>
			<name>Sebastian Bergmann</name>
			<email>nospam@example.com</email>
			<uri>http://sebastian-bergmann.de/</uri>
		</author>
		<source>
			<title type="html">Sebastian Bergmann - PHPUnit</title>
			<link rel="self" href="http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss"/>
			<id>http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss</id>
			<updated>2010-08-19T08:00:26+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">phpUnderControl 0.5.1 released</title>
		<link href="http://www.manuel-pichler.de/archives/79-phpUnderControl-0.5.1-released.html"/>
		<id>http://www.manuel-pichler.de/archives/79-guid.html</id>
		<updated>2010-01-31T20:16:35+00:00</updated>
		<content type="html">&lt;p&gt;
  Today I have released &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2246&amp;entry_id=79&quot; title=&quot;http://phpundercontrol.org&quot;&gt;phpUnderControl&lt;/a&gt; version &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2247&amp;entry_id=79&quot; title=&quot;http://github.com/manuelpichler/phpUnderControl/tree/0.5.1&quot;&gt;0.5.1&lt;/a&gt;. It's a bug fix release that closes several issues open since a long time. First of all I would like to thank &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2248&amp;entry_id=79&quot; title=&quot;http://twitter.com/proofek&quot;&gt;Sebastian Marek&lt;/a&gt; who was the main contributor to this releases, so a big thankyou to you.
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Now phpUnderControl should work with &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2265&amp;entry_id=79&quot; title=&quot;http://cruisecontrol.sourceforge.net&quot;&gt;CruiseControl 2.8.3&lt;/a&gt;. Thanks to Mike van Riel who provided some hints on this issue in a &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2249&amp;entry_id=79&quot; title=&quot;http://manuel-pichler.de/archives/69-phpUnderControl-0.5.0-released.html#c350&quot;&gt;blog comment&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Fixed &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2250&amp;entry_id=79&quot; title=&quot;http://www.phpunit.de/ticket/983&quot;&gt;#983&lt;/a&gt;: Graph unitests throw fatal error when ezComponents not available.&lt;/li&gt;
  &lt;li&gt;Fixed &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2251&amp;entry_id=79&quot; title=&quot;http://www.phpunit.de/ticket/966&quot;&gt;#966&lt;/a&gt;: phpcs-details.xsl not showing file name.&lt;/li&gt;
  &lt;li&gt;Closed &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2252&amp;entry_id=79&quot; title=&quot;http://www.phpunit.de/ticket/863&quot;&gt;#863&lt;/a&gt;: Destination option is now deprecated.&lt;/li&gt;
  &lt;li&gt;Fixed &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2253&amp;entry_id=79&quot; title=&quot;http://www.phpunit.de/ticket/862&quot;&gt;#862&lt;/a&gt;: Command line switches without parameter don't work.&lt;/li&gt;
  &lt;li&gt;Fixed &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2254&amp;entry_id=79&quot; title=&quot;http://www.phpunit.de/ticket/861&quot;&gt;#861&lt;/a&gt;: Password is used as username in check outs. This patch was supplied by Thorsten Daners via e-mail.&lt;/li&gt;
  &lt;li&gt;Fixed &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2255&amp;entry_id=79&quot; title=&quot;http://www.phpunit.de/ticket/734&quot;&gt;#734&lt;/a&gt;: Now the build dropdown redirects to the correct build uri.&lt;/li&gt;
  &lt;li&gt;Implemented &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2256&amp;entry_id=79&quot; title=&quot;http://www.phpunit.de/ticket/703&quot;&gt;#703&lt;/a&gt;: PHPUnit test results are now the first entry on the project overview page.&lt;/li&gt;
  &lt;li&gt;Fixed &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2257&amp;entry_id=79&quot; title=&quot;http://www.phpunit.de/ticket/700&quot;&gt;#700&lt;/a&gt;: Throw an exception when the specified project does not exist.&lt;/li&gt;
  &lt;li&gt;Implemented &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2258&amp;entry_id=79&quot; title=&quot;http://www.phpunit.de/ticket/675&quot;&gt;#675&lt;/a&gt;: Use &quot;php -l&quot; for lint checking and not PHPUnit.&lt;/li&gt;
  &lt;li&gt;Implemented &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2259&amp;entry_id=79&quot; title=&quot;http://www.phpunit.de/ticket/625&quot;&gt;#625&lt;/a&gt;: Integrate PHP_Depend results.&lt;/li&gt;
&lt;/ul&gt;

&lt;br /&gt;
&lt;p&gt;
  Beside the new release some more things have changed. From now on the phpUnderControl development is hosted on &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2260&amp;entry_id=79&quot; title=&quot;http://github.com&quot;&gt;github&lt;/a&gt;. This means that from now on the latest version of phpUnderControl can be obtained with the following command:
&lt;/p&gt;

&lt;pre&gt;
mapi@arwen ~ $ git clone \
               git://github.com/manuelpichler/phpUnderControl.git
&lt;/pre&gt;

&lt;p&gt;
Additionally we have moved the phpUnderControl's PEAR Channel Server from &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2261&amp;entry_id=79&quot; title=&quot;http://pear.phpunit.de&quot;&gt;pear.phpunit.de&lt;/a&gt; to its own server &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2262&amp;entry_id=79&quot; title=&quot;http://pear.phpundercontrol.org&quot;&gt;pear.phpundercontrol.org&lt;/a&gt;. At this point I would like to thank &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2263&amp;entry_id=79&quot; title=&quot;http://sebastian-bergmann.de/&quot;&gt;Sebastian&lt;/a&gt; for providing phpUnderControl's infrastructure under the &lt;a href=&quot;http://www.manuel-pichler.de/exit.php?url_id=2264&amp;entry_id=79&quot; title=&quot;http://phpun.it&quot;&gt;PHPUnit umbrella&lt;/a&gt; for the last three years.
&lt;/p&gt;

&lt;pre&gt;
mapi@arwen ~ $ pear uninstall phpunit/phpUnderControl
mapi@arwen ~ $ pear channel-discover pear.phpundercontrol.org
mapi@arwen ~ $ pear install --alldeps phpuc/phpUnderControl-beta
Starting to download phpUnderControl-0.5.1.tgz (539,717 bytes)
..........................................done: 539,717 bytes
install ok: channel://pear.phpundercontrol.org/phpUnderControl-0.5.1
&lt;/pre&gt;</content>
		<author>
			<name>Manuel Pichler</name>
			<email>nospam@example.com</email>
			<uri>http://www.manuel-pichler.de/</uri>
		</author>
		<source>
			<title type="html">Manuel Pichler - phpundercontrol</title>
			<subtitle type="html">Trust is good, (phpUnder)Control is better.</subtitle>
			<link rel="self" href="http://manuel-pichler.de/feeds/categories/10-phpundercontrol.rss"/>
			<id>http://manuel-pichler.de/feeds/categories/10-phpundercontrol.rss</id>
			<updated>2010-06-10T11:00:28+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">CRAP in PHPUnit 3.5</title>
		<link href="http://sebastian-bergmann.de/archives/877-CRAP-in-PHPUnit-3.5.html"/>
		<id>http://sebastian-bergmann.de/archives/877-guid.html</id>
		<updated>2010-01-12T09:30:00+00:00</updated>
		<content type="html">&lt;p&gt;For the upcoming &lt;a href=&quot;http://www.phpunit.de/&quot;&gt;PHPUnit 3.5&lt;/a&gt;, I have factored out all code that is related to &lt;a href=&quot;http://en.wikipedia.org/wiki/Code_coverage&quot;&gt;code coverage&lt;/a&gt; and put it into a separate component: &lt;a href=&quot;http://github.com/sebastianbergmann/php-code-coverage&quot;&gt;PHP_CodeCoverage&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;PHP_CodeCoverage is a component that provides collection, processing, and rendering functionality for PHP code coverage information. It makes PHPUnit's mature code coverage functionality available outside of PHPUnit.&lt;/p&gt;

&lt;p&gt;Having all code that deals with code coverage in a separate component allows for easier development and better testing. The first result of these improved development conditions is a small new feature that I recently implemented, the support for the &lt;acronym title=&quot;Change Risk Analysis and Predictions&quot;&gt;CRAP&lt;/acronym&gt; metric.&lt;/p&gt;

&lt;p&gt;From &lt;a href=&quot;http://www.crap4j.org/&quot;&gt;crap4j.org&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;The CRAP (Change Risk Analysis and Predictions) software metric [has] a mildly offensive metric name [and helps] to help protect you from truly offensive code.&lt;/p&gt;
&lt;p&gt;The CRAP metric combines &lt;a href=&quot;http://en.wikipedia.org/wiki/Cyclomatic_complexity&quot;&gt;cyclomatic complexity&lt;/a&gt; and code coverage from automated tests (e.g. [PHPUnit] tests) to help you identify code that might be particularly difficult to understand, test, or maintain &amp;mdash; the kind of code that makes developers say: &#8220;This is crap!&#8221; or, if they are stuck maintaining it, &#8220;Oh, crap!&#8221;.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;The screenshot below shows how the CRAP metric is reported in the HTML code coverage report:&lt;/p&gt;

&lt;a href=&quot;http://sebastian-bergmann.de/uploads/crap.png&quot;&gt;&lt;img alt=&quot;Code Coverage Report&quot; border=&quot;0&quot; src=&quot;http://sebastian-bergmann.de/uploads/crap-highlight.png&quot; /&gt;&lt;/a&gt;</content>
		<author>
			<name>Sebastian Bergmann</name>
			<email>nospam@example.com</email>
			<uri>http://sebastian-bergmann.de/</uri>
		</author>
		<source>
			<title type="html">Sebastian Bergmann - PHPUnit</title>
			<link rel="self" href="http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss"/>
			<id>http://sebastian-bergmann.de/feeds/categories/14-PHPUnit.rss</id>
			<updated>2010-08-19T08:00:26+00:00</updated>
		</source>
	</entry>

	<entry xml:lang="en">
		<title type="html">PHPUnit Development Moved to GitHub</title>
		<link href="http://sebastian-bergmann.de/archives/876-PHPUnit-Development-Moved-to-GitHub.html"/>
		<id>http://sebastian-bergmann.de/archives/876-guid.html</id>
		<updated>2009-12-26T10:45:00+00:00</updated>
		<content type="html">&lt;p&gt;Over the Christmas holidays I took a break from translating and editing the
&lt;a href=&quot;http://phpqabook.com/&quot;&gt;book on quality assurance in PHP projects&lt;/a&gt;
that I am working on to finally migrate the code repository of
&lt;a href=&quot;http://www.phpunit.de/&quot;&gt;PHPUnit&lt;/a&gt; from a self-hosted
&lt;a href=&quot;http://subversion.tigris.org/&quot;&gt;Subversion&lt;/a&gt; repository to a
&lt;a href=&quot;http://git-scm.com/&quot;&gt;Git&lt;/a&gt; repository that is hosted on
&lt;a href=&quot;http://github.com/&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;How did I get here?&lt;/h3&gt;

&lt;p&gt;I was staying at &lt;a href=&quot;http://openquery.com/&quot;&gt;Arjen&lt;/a&gt;'s place in Brisbane
in August 2008 and one day we talked about distributed version control. Although I
knew the basic concepts behind it, I was not yet convinced enough to take the
plunge and try it out. Our discussion changed that, but it was not until my
second trip to Australia later that year that I took the initial code for
PHP_ObjectFreezer (which I had on my laptop since I started to hack on it
together with &lt;a href=&quot;http://www.priebsch.de/&quot;&gt;Stefan&lt;/a&gt; on the flight to
Atlanta for php|works 2008) and put it into a
&lt;a href=&quot;http://bazaar.canonical.com/en/&quot;&gt;bzr&lt;/a&gt; repository on
&lt;a href=&quot;http://launchpad.net/&quot;&gt;Launchpad&lt;/a&gt;. I grew comfortable enough with
bzr quickly, but never really warmed up to Launchpad.&lt;/p&gt;

&lt;p&gt;Around that time, I was hearing more and more positive things about Git and
GitHub from my peers. So I took the PHP_ObjectFreezer code base and migrated it
to Git and hosted the repository and GitHub to experiment with both the tool and
the platform. It was a step that I did not regret and all the projects that I
started since then are hosted on GitHub:
&lt;a href=&quot;http://github.com/sebastianbergmann/bytekit-cli&quot;&gt;bytekit-cli&lt;/a&gt;,
&lt;a href=&quot;http://github.com/sebastianbergmann/phpcpd&quot;&gt;phpcpd&lt;/a&gt;,
&lt;a href=&quot;http://github.com/sebastianbergmann/phpdcd&quot;&gt;phpdcd&lt;/a&gt;,
&lt;a href=&quot;http://github.com/sebastianbergmann/phploc&quot;&gt;phploc&lt;/a&gt;,
&lt;a href=&quot;http://github.com/sebastianbergmann/php-code-coverage&quot;&gt;PHP_CodeCoverage&lt;/a&gt;,
&lt;a href=&quot;http://github.com/sebastianbergmann/php-file-iterator&quot;&gt;PHP_FileIterator&lt;/a&gt;,
&lt;a href=&quot;http://github.com/sebastianbergmann/php-object-freezer&quot;&gt;PHP_ObjectFreezer&lt;/a&gt;,
&lt;a href=&quot;http://github.com/sebastianbergmann/php-text-template&quot;&gt;Text_Template&lt;/a&gt;,
&lt;a href=&quot;http://github.com/sebastianbergmann/php-token-stream&quot;&gt;PHP_TokenStream&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Why did I do this?&lt;/h3&gt;

&lt;p&gt;Let me start with a quote from GitHub.com:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;&lt;li&gt;Git is a fast, efficient, distributed version control system ideal for the collaborative development of software.&lt;/li&gt;
&lt;li&gt;GitHub is the easiest (and prettiest) way to participate in that collaboration: fork projects, send pull requests, monitor development, all with ease.&lt;/li&gt;&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Over the last year, I have come to appreciate Git and GitHub a lot and also
wanted to use them for PHPUnit.&lt;/p&gt;&lt;p&gt;Sure, I could have used &lt;a href=&quot;http://www.kernel.org/pub/software/scm/git/docs/git-svn.html&quot;&gt;git-svn&lt;/a&gt;
for bi-directional operation between the existing Subversion repository and Git,
but this would have always felt like only going half the way.&lt;/p&gt;&lt;p&gt;The arguments in
favour of distributed version control systems are discussed by others far better
than I could discuss them here, so I will just quote Ian Clatworthy's
&lt;a href=&quot;http://ianclatworthy.files.wordpress.com/2007/10/dvcs-why-and-how3.pdf&quot;&gt;paper on distributed version control systems&lt;/a&gt;,
in which discusses not only the technical differences between traditional
version control systems and distributed version control systems, but also the
differences with regard to development workflows and developer interaction:&lt;/p&gt;
&lt;blockquote&gt;&lt;ul&gt;&lt;li&gt;Developers can collaborate directly without needing central
authority or incurring central administration overhead&lt;/li&gt;&lt;li&gt;Developers can
still be productive when the umbilical cord to their central VCS repository is
broken, e.g. when travelling.&lt;/li&gt;&lt;li&gt;Creating and destroying branches are
simple operations. This is particularly useful when experimenting with new
ideas, e.g. a &lt;i&gt;spike&lt;/i&gt; when using &lt;a href=&quot;http://en.wikipedia.org/wiki/Extreme_Programming&quot;&gt;eXtreme Programming&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Ad-hoc collaboration with peers [is facilitated by] intelligent merge
tracking [because] merging early and merging often is both possible and
surprisingly unpainful. It is difficult to explain just how much of an impact
this can make on how co-developers can work together more easily, e.g. when
&lt;a href=&quot;http://en.wikipedia.org/wiki/Pair_Programming&quot;&gt;Pair Programming&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;

&lt;h3&gt;What does this mean for you?&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://github.com/sebastianbergmann/phpunit&quot;&gt;PHPUnit is now hosted
on GitHub.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In a nutshell, this means that the development of PHPUnit is now more open
than it was before. If you want to contribute, you just need to
&lt;a href=&quot;http: