Testing your Agavi application with NetBeans and PHPUnit
I’ve been aware of NetBeans’ PHPUnit supportĀ for quite a while, and it looked quite nice in the screenshots. However, the Agavi testing subsystem (still alpha alpha alpha, as I was yelled at today) is rather awkward and inflexible the way it is put to use in the sample application that is provided with the Agavi download, and there didn’t seem to be an easy way to get it working with NetBeans. So today I thought “I’ll be damned if I can’t get that to work”.
A word of warning: The Agavi testing subsystem does not currently run some of the global filters (or all of them?). Among these are FormPopulationFilter, and this renders the flow tests next to useless, as you cannot test that the templates have gotten, say, the right error messages injected. There is apparently also something that causes the “released” versions of PHPUnit 3.4.x to not work properly with Agavi tests. I will try to discover what this is all about and what is affected by it.
Right. As the released versions of PHPUnit is out of the question, we’ll do a bit of trickery. The version bundled with Agavi (under vendor/PHPUnit) works, so we’ll grab that version from PHPUnit’s repository and build our own PHPUnit. The version bundled with Agavi 1.0.2 is revision 5395. We’ll create a temporary directory, check out the revision, build a PEAR package out of it and install it:
Y:\>mkdir temp
Y:\>cd temp
Y:\temp>svn co -r5395 svn://svn.phpunit.de/
phpunit/phpunit/tags/3.4.3 PHPUnit
Y:\temp>cd PHPUnit
Y:\temp\PHPUnit>pear package
Y:\temp\PHPUnit>pear install PHPUnit-3.4.3.tgz
The SVN-command is on one line.
Fire up NetBeans and select Tools => Options => PHP => Unit Testing and set the PHPUnit script to where your phpunit.bat resides. Mine’s at C:\php\phpunit.bat.
I’m using Bloggie from the Agavi tutorial as an example here, but it should work with any project. If you haven’t got it, you can grab it from http://www.agavi.org/guide/stages/stage8.tgz. Extract it somewhere, create a new PHP project with existing sources in NetBeans and set the source directory to where ever you extracted Bloggie.
We’ll create a small unit test for Bloggie’s UserManagerModel, so go ahead and create a directory structure similar to this:

Now, to get things working, we’ll need to configure PHPUnit. I do this through a really simple phpunit.xml-file under bloggie/test, and it’ll look something like this:
01 <phpunit bootstrap="bootstrap.php"> 02 <testsuite name="BloggieTests"> 03 <file>./tests/unit/UserManagerModelTest.php</file> 04 </testsuite> 05 </phpunit>
What we are doing here is telling PHPUnit that we need a bootstrap file to set up the environment before running any tests. Then we create a very simple test suite with one test, UserManagerModelTest.php. Don’t worry, we’ll create this file later.
In the same directory, create a new PHP file and call it bootstrap.php. We’ll simply do a die() in it so that we can see that everything is working properly.
01 <?php 02 die("Hello, world!"); 03 ?>
Now we need to tell PHPUnit to use our files: right click on your project and select “Properties” from the context menu. Under “Categories” you should see “PHPUnit”. Select it, check both the “Use Bootstrap” and “Use XML Configuration” -checkboxes and select the right files, and click “Ok”.
Right-click on your project and select “test” from the context menu, and if everything is working correctly you should see something like this:

Switch to the output window (Ctrl-4) and you should see:

That means that PHPUnit is configured properly, reading its phpunit.xml and running the bootstrap file! Brilliant!
Next, onto the bootstrap file.
What we need to do here is to configure the Agavi environment so that the framework itself is up and running.
01 <?php 02 $there = realpath(dirname(__FILE__) . '/../libs/agavi'); 03 04 set_include_path($there . PATH_SEPARATOR . 05 realpath($there . '/testing') . PATH_SEPARATOR .
06 get_include_path()); 07
08 // load Agavi basics 09 require_once($there . '/agavi.php'); 10 11 // AgaviTesting class 12 require_once($there . '/testing/AgaviTesting.class.php'); 13 14 AgaviConfig::set('core.testing_dir', realpath(dirname(__FILE__))); 15 AgaviConfig::set('core.app_dir', realpath(dirname(__FILE__).'/../app/')); 16 AgaviConfig::set('core.default_context', 'console'); 17 18 AgaviTesting::bootstrap('production'); 19 ?>
First, we grab the absolute path to agavi (in my case Y:\Projects\bloggie\libs\agavi) and store it in $there and set the include path to the agavi dir and the testing dir. Then we include the main Agavi script, and the AgaviTesting class. We also need to set some configuration values, but those should be fairly obvious. Lastly we set up AgaviTesting with the production environment. I run tests in production, otherwise Agavi would clear the configuration cache and parse all settings and generate new cache files for every single test (which is how Rasmus Lerdorf mucked up his review of PHP frameworks, btw).
Now, let’s create a simple test to see that PHPUnit also works! Create the file UserManagerModelTest.php in the test/tests/unit/model -directory. For our first test it will look like this:
01 <?php 02 class UserManagerModelTest extends AgaviUnitTestCase 03 { 04 public function testSetup() 05 { 06 $this->assertTrue(true); 07 } 08 09 } 10 ?>
What we do here is just test that the setup is working (asserting that true === true). Go ahead and run the test, and if everything works you should see

It’s working! Sweet! Onwards to a proper test!
Modify the UserManagerModelTest -file to look like this:
01 <?php 02 03 class UserManagerModelTest extends AgaviUnitTestCase 04 { 05 06 public function testThatShouldFail() 07 { 08 $this->assertTrue(false); 09 } 10 11 public function testRetrieveByCorrectId() 12 { 13 /* @var $userManager UserManagerModel */ 14 $userManager = $this->getContext()->getModel('UserManager'); 15 $user = $userManager->retrieveById('chuck'); 16 $this->assertTrue($user instanceof UserModel); 17 } 18 19 public function testRetrieveByIncorrectId() 20 { 21 /* @var $userManager UserManagerModel */ 22 $userManager = $this->getContext()->getModel('UserManager'); 23 24 try { 25 $user = $userManager->retrieveById('arnold'); 26 $this->fail('No exception thrown'); 27 } catch (Exception $e) { 28 $this->assertEquals("invalid user specified", $e->getMessage()); 29 } 30 31 } 32 33 } 34 35 ?>
What we do here is first define a test that we KNOW will fail (just so we can see the pretty colours in NetBeans), then in the second test grab the UserManagerModel from the Agavi context and try to retrieve a user with the id “chuck”, which should be successful. In the third test we try to grab a user with the id “arnold”, which should throw an error, and if it DOES throw an error the test passes.
Right, let’s run the tests and see what happens!

HUGE SUCCESS! The test results show a red and two green tests (see what I did there, TDD-people)!
This, of course, has been a small introduction, and I’ll write some more about testing and Agavi once I have things set up for our main project.
Happy testing!
Bootnote: For some reason I get a
RuntimeException: PHP Fatal error: Cannot
redeclare class AgaviXmlConfigXsltProcessor in
Y:\Projects\bloggie\libs\agavi\config\util\xsl\
AgaviXmlConfigXsltProcessor.class.php on line 117
error when I run the tests on my laptop unless I comment out the ini_set in Bloggie’s config.php. I’ll try to figure out what’s causing it ASAP.
Update: I fixed the code highlighting stuff a bit, should look a bit better now.
Update 2: Aaand I made a terrible mess out of it. Will fix ASAP.
Update 3: Should be fixed now. I daren’t touch this any more now! Terribly sorry for the mess.
1 Notes/ Hide
-
careerprogrammer liked this
-
necora-markus posted this