SlideShare a Scribd company logo
Advanced PHP Unit Testing The 2008 DC PHP Conference June 2nd, 2008
Hello! Mike Lively Lead Developer Selling Source, Inc. PHPUnit Contributor PHPUnit Database Extension A frequent inhabitant of #phpc http://digitalsandwich.com
PHPUnit A widely used unit testing framework Created by Sebastian Bergmann Originally built as a port of Junit Now incredibly feature rich
PHPUnit - Advanced Features Mock Objects - A way to further isolate code while testing. Database Extension - A DBUnit port to allow creation of fixtures for database content. Selenium Integration - A gateway to integration testing. PHPUnderControl - Not really PHPUnit...but still very cool. Much to cover and not much of time. Let's get started!
PHPUnit - Mock Objects Mock Objects - A way to further isolate code while testing. Creates 'Fake' objects that mimic 'real' objects in controlled ways. Used to ensure that expected methods are being called in expected ways. Used to ensure that methods that are depended on by the unit you are testing do not 'pollute' your test with their behavior.
PHPUnit - Mock Objects How do I ensure a method is called properly?
PHPUnit - Mock Objects How do I ensure a method is called properly? Create a mock object! PHPUnit_Framework_TestCase::getMock(   string $className,   array $methods = array(),   array $constructParms = array(),   string $mockClassName = '',   bool $callOriginalConstruct = TRUE,   bool $callOriginalClone = TRUE,   bool $callAutoLoad = TRUE );
PHPUnit - Mock Objects Create the mock object <?php require_once  'PHPUnit/Framework.php' ;   class  ObserverTest  extends  PHPUnit_Framework_TestCase {     public function  testUpdateIsCalledOnce ()     {          $observer  =  $this -> getMock ( 'Observer' , array( 'update' ));     } } ?>
PHPUnit - Mock Objects Setup the expectation <?php require_once  'PHPUnit/Framework.php' ;   class  ObserverTest  extends  PHPUnit_Framework_TestCase {     public function  testUpdateIsCalledOnce ()     {          $observer  =  $this -> getMock ( 'Observer' , array( 'update' ));          $observer -> expects ( $this -> once ())                  -> method ( 'update' )                  -> with ( $this -> equalTo ( 'something' ));     } } ?>
PHPUnit - Mock Objects expects() - Sets how many times you expect a method to be called: any()‏ never()‏ atLeastOnce()‏ once()‏ exactly($count)‏ at($index) method() - The name of the method you are setting the expectation for
PHPUnit - Mock Objects with() - Each parameter is validated using PHPUnit Constraints: anything()‏ contains($value)‏ arrayHasKey($key)‏ equalTo($value, $delta, $maxDepth)‏ classHasAttribute($attribute)‏ greaterThan($value)‏ isInstanceOf($className)‏ isType($type)‏ matchesRegularExpression($regex)‏ stringContains($string, $case) withAnyParameters() - A quick way to say &quot;I don't care&quot;
PHPUnit - Mock Objects Call the tested code <?php require_once  'PHPUnit/Framework.php' ;   class  ObserverTest  extends  PHPUnit_Framework_TestCase {     public function  testUpdateIsCalledOnce ()     {          $observer  =  $this -> getMock ( 'Observer' , array( 'update' ));          $observer -> expects ( $this -> once ())                  -> method ( 'update' )                  -> with ( $this -> equalTo ( 'something' ));          $subject  = new  Subject ;          $subject -> attach ( $observer );            $subject -> doSomething ();     } } ?>
PHPUnit - Mock Objects Force methods not being tested to return particular values. will() - Force the current method to return a particular value returnValue($value) - Returns the specified value throwException($exception) - Throws the specified exception object onConsecutiveCalls(...) - Performs each action (return or exception) consecutively.
PHPUnit - Mock Objects Forcing methods to return certain values <?php require_once  'PHPUnit/Framework.php' ;   class  StubTest  extends  PHPUnit_Framework_TestCase {     public function  testStub ()     {          $stub  =  $this -> getMock ( 'SomeClass' , array( 'doSomething' ));          $stub -> expects ( $this -> any ())              -> method ( 'doSomething' )              -> will ( $this -> returnValue ( 'foo' ));            // Calling $stub->doSomething() will now return 'foo'.      } } ?>
PHPUnit - Database Extension The PHPUnit Database Extension
PHPUnit - Database Extension PHPUnit Database Extension - DBUnit Port Uses many of the same concepts Dataset formats are essentially identical Puts your database into a known state prior to testing Allows for setting expectations of data in your database at the end of a test
PHPUnit - Database Extension PHPUnit_Extensions_Database_TestCase Overloads setUp() and tearDown() and introduces four new overridable methods (2 MUST be overriden) If implementing setUp or tearDown, please be sure to call parent::setUp() and parent::tearDown()‏
PHPUnit - Database Extension Must implement getConnection() - Returns a database connection wrapper getDataSet() - Returns the dataset to seed the test database with. Can override getSetUpOperation() - Returns the operation used to set up the database (defaults to CLEAN_INSERT) getTearDownOperation() - Returns the operation to used to tear down the database (defaults to NONE)‏
PHPUnit - Database Extension getConnection() returns a customized wrapper around a database connection. Current implementation uses PDO This does not mean code you are testing has to use PDO createDefaultDBConnection(   PDO $pdo,    string $schema ); // Convenience method Very important to provide the schema name.
PHPUnit - Database Extension Setting up your database test case connection <?php require_once  'PHPUnit/Extensions/Database/TestCase.php' ;   class  DatabaseTest  extends  PHPUnit_Extensions_Database_TestCase {     protected function  getConnection ()     {          $pdo  = new  PDO ( 'mysql:host=localhost;dbname=testdb' ,  'root' ,  '' );         return  $this -> createDefaultDBConnection ( $pdo ,  'testdb' );     } } ?>
PHPUnit - Database Extension Currently (known) supported databases: MySQL SQLite Postgres OCI8 Need another RDBMS supported? I NEED YOU!!!
PHPUnit - Database Extension getDataSet() returns one of the following types of data sets: Flat XML XML Database Default (php array basically) Can be a pain to create Working on utilities to make it...less painful
PHPUnit - Database Extension Convenience methods for datasets $this->createFlatXMLDataSet($xmlFile); $this->createXMLDataSet($xmlFile); Use full paths
PHPUnit - Database Extension Setting up your database test case's common fixture <?php require_once  'PHPUnit/Extensions/Database/TestCase.php' ;   class  DatabaseTest  extends  PHPUnit_Extensions_Database_TestCase {     protected function  getConnection ()     {          $pdo  = new  PDO ( 'mysql:host=localhost;dbname=testdb' ,  'root' ,  '' );         return  $this -> createDefaultDBConnection ( $pdo ,  'testdb' );     }       protected function  getDataSet ()     {         return  $this -> createFlatXMLDataSet ( dirname ( __FILE__ ). '/_files/bank-account-seed.xml' );     } } ?>
PHPUnit - Flat XML Data Set Each element represents a row, each attribute represents a column. All attributes must be present in the first element for a given table. Specifying an element with no attributes represents an empty table. If an attribute specified in the first element is missing in subsequent element, NULL is implied. There is no explicit NULL
PHPUnit - Database Extension Flat XML <dataset>      <TEST_TABLE COL0=&quot;row 0 col 0&quot;           COL1=&quot;row 0 col 1&quot;          COL2=&quot;row 0 col 2&quot;/>       <TEST_TABLE COL1=&quot;row 1 col 1&quot;/>      <SECOND_TABLE COL0=&quot;row 0 col 0&quot;           COL1=&quot;row 0 col 1&quot; />      <EMPTY_TABLE/> </dataset>
PHPUnit - XML Data Set A more robust and capable format <table> element for each table <column> element for each column <row> element for each row <row> will contain equal number of children as there are <column>s in the same order. <value>val</value> is used to specify a value <null/> used to explicitly specify NULL
PHPUnit - Database Extension XML (Not so flat)‏ <dataset>     <table name=&quot;TEST_TABLE&quot;>         <column>COL0</column>         <column>COL1</column>         <column>COL2</column>         <row>             <value>row 0 col 0</value>             <value>row 0 col 1</value>             <value>row 0 col 2</value>         </row>         <row>             <null/>             <value>row 1 col 1</value>             <null/>         </row>     </table>     <table name='EMPTY_TABLE'>         <column>COLUMN0</column>         <column>COLUMN1</column>     </table> </dataset>
PHPUnit - Other Data Sets Pull your data sets out of a database Possible, and might be a good way to do it for smaller database test suites. Wouldn't recommend it for large ones (yet) What about the Default data set? I haven't hated myself enough to bother with it yet :P Future formats? CSV, Composite Data Sets, Query Sets
PHPUnit - Other Data Sets Pull your data sets out of a database Possible, and might be a good way to do it for smaller database test suites. Wouldn't recommend it for large ones (yet) What about the Default data set? I haven't hated myself enough to bother with it yet :P Future formats? CSV, Composite Data Sets, Query Sets  <- this is when you'll want to use database data sets for large suites
PHPUnit - Operations If you want to specify non-default operations override either getSetUpOperation() or getTearDownOperation() with a static method from the class: PHPUnit_Extensions_Database_Operation_Factory  NONE CLEAN_INSERT INSERT TRUNCATE DELETE DELETE_ALL UPDATE
PHPUnit - Operations <?php require_once  'PHPUnit/Extensions/Database/TestCase.php' ;   class  DatabaseTest  extends  PHPUnit_Extensions_Database_TestCase {     protected function  getSetUpOperation ()     {         return  PHPUnit_Extensions_Database_Operation_Factory :: CLEAN_INSERT ();     }       protected function  getTearDownOperation ()     {         return  PHPUnit_Extensions_Database_Operation_Factory :: NONE ();     } } ?>
PHPUnit - Database Extension Setting up database expectations. Retrieve database contents: $this->getConnection()->createDataSet(); Creates a dataset with ALL data in your database. Pass an array of table names if you only want to compare particular tables. You can also use the data set filter if necessary
PHPUnit - Database Extension Why Filtered Data Sets? auto increment, time stamps PHPUnit_Extensions_Database_DataSet_DataSetFilter decorator Accepts existing dataset object as first parameter Accepts associative array as second parameter The array indexes are table names The array values are arrays of column names to exclude from the data set or the string '*' if the whole table is to be excluded.
PHPUnit - Database Extension Refreshing our memory <?php require_once  'PHPUnit/Extensions/Database/TestCase.php' ;   class  DatabaseTest  extends  PHPUnit_Extensions_Database_TestCase {     protected function  getConnection ()     {          $pdo  = new  PDO ( 'mysql:host=localhost;dbname=testdb' ,  'root' ,  '' );         return  $this -> createDefaultDBConnection ( $pdo ,  'testdb' );     }       protected function  getDataSet ()     {         return  $this -> createFlatXMLDataSet ( dirname ( __FILE__ ). '/_files/bank-account-seed.xml' );     } } ?>
PHPUnit - Database Extension Writing a test <?php require_once  'PHPUnit/Extensions/Database/TestCase.php' ;   class  DatabaseTest  extends  PHPUnit_Extensions_Database_TestCase {      // ...     public function  testAccountBalanceDeposits ()     {          $bank_account  = new  BankAccount ( '15934903649620486' ,  $this -> pdo );          $bank_account -> depositMoney ( 100 );               $bank_account  = new  BankAccount ( '15936487230215067' ,  $this -> pdo );          $bank_account -> depositMoney ( 230 );                   $bank_account  = new  BankAccount ( '12348612357236185' ,  $this -> pdo );          $bank_account -> depositMoney ( 24 );                    $xml_dataset  =  $this -> createFlatXMLDataSet ( dirname ( __FILE__ ). '/_files/bank-account-after-deposits.xml' );          $database_dataset = $this -> getConnection ()-> createDataSet ( array ( 'bank_account' ));     }       // ... } ?>
PHPUnit - Database Extension Filtering out date_created <?php require_once  'PHPUnit/Extensions/Database/TestCase.php' ;   class  DatabaseTest  extends  PHPUnit_Extensions_Database_TestCase {      // ...     public function  testAccountBalanceDeposits ()     {          // ...                   $xml_dataset  =  $this -> createFlatXMLDataSet ( dirname ( __FILE__ ). '/_files/bank-account-after-deposits.xml' );   $database_dataset =  new  PHPUnit_Extensions_Database_DataSet_DataSetFilter (   $this -> getConnection ()-> createDataSet ( array ( 'bank_account' )),    array ( 'bank_account'  =>  array ( 'date_created' ))   );   }       // ... } ?>
PHPUnit - Database Extension $this->assertDataSetsEqual($expected, $actual) Compares all tables in the two data sets Must have equal and matching tables with equal and matching data Have I mentioned filters? $this->assertTablesEqual($expected, $actual) There is also a table filter!
PHPUnit - Database Extension Writing a test <?php require_once  'PHPUnit/Extensions/Database/TestCase.php' ;   class  DatabaseTest  extends  PHPUnit_Extensions_Database_TestCase {      // ...     public function  testAccountBalanceDeposits ()     {          $bank_account  = new  BankAccount ( '15934903649620486' ,  $this -> pdo );          $bank_account -> depositMoney ( 100 );               $bank_account  = new  BankAccount ( '15936487230215067' ,  $this -> pdo );          $bank_account -> depositMoney ( 230 );                   $bank_account  = new  BankAccount ( '12348612357236185' ,  $this -> pdo );          $bank_account -> depositMoney ( 24 );                    $xml_dataset  =  $this -> createFlatXMLDataSet ( dirname ( __FILE__ ) .  '/_files/bank-account-after-deposits.xml' );   $this -> assertDataSetsEqual (   $xml_dataset ,            $this -> getConnection ()-> createDataSet ( array ( 'bank_account' ))   );     }       // ... } ?>
PHPUnit - Selenium Selenium is a testing framework for web applications. Runs tests by controlling a remote browser session Can inspect the dom, look for events, and much much more Selenium tests can be made a part of your PHPUnit Test Suite
PHPUnit - Selenium Selenium is a testing framework for web applications. Runs tests by controlling a remote browser session Can inspect the dom, look for events, and much much more Selenium tests can be made a part of your PHPUnit Test Suite
PHPUnit - Selenium Demo Time!
PHPUnit - Continuous Integration Continuous Integration is a software development practice where members of a team integrate their work frequently, usually each person integrates at least daily, leading to multiple integrations per day. Each integration is verified by an automated build (including test) to detect integration errors as quickly as possible. Many teams find that this approach leads to significantly reduced integration problems and allows a team to develop cohesive software more rapidly.  -- Martin Fowler
PHPUnit - PHPUnderControl Created and maintained by Manuel Pischler Cruise Control for the php developer Runs your Unit Tests Builds your documentation Lint checks your code Gives you build and performance metrics The best thing since sliced bread
PHPUnit - PHPUnderControl Demo Time!
Thank you - Resources PHPUnit: http://phpun.it,  http://planet.phpunit.de Selenium:  http://selenium.openqa.org/ PHPUnderControl:  http://www.phpundercontrol.org/ My Site:  http://www.digitalsandwich.com My Employer's Site: http://dev.sellingsource.com Questions??

More Related Content

PPTX
Unit Testng with PHP Unit - A Step by Step Training
PPTX
PHPUnit: from zero to hero
PDF
Curso de Java: Introdução a lambda e Streams
PPTX
Introduction à Angular
PPTX
Laravel
PDF
Design patterns
PPTX
Files in php
PDF
Remote Method Invocation in JAVA
Unit Testng with PHP Unit - A Step by Step Training
PHPUnit: from zero to hero
Curso de Java: Introdução a lambda e Streams
Introduction à Angular
Laravel
Design patterns
Files in php
Remote Method Invocation in JAVA

What's hot (20)

PDF
Chap 4 PHP.pdf
PPT
Class 3 - PHP Functions
DOCX
Servlet
PPTX
Introduction à Symfony
PPT
Php Error Handling
ODP
Introduction to Perl - Day 2
PPT
Node.js Express Framework
PPT
01 Php Introduction
PDF
POCO C++ Libraries Intro and Overview
PDF
4.2 PHP Function
PPTX
Php basics
PPTX
Method overloading
PDF
Quick flask an intro to flask
PDF
JavaScript Promises
PPTX
Javascript Design Patterns
PPTX
Php string function
PPT
Test Driven Development with PHPUnit
PPTX
React + Redux Introduction
PPTX
Object oriented programming concepts
Chap 4 PHP.pdf
Class 3 - PHP Functions
Servlet
Introduction à Symfony
Php Error Handling
Introduction to Perl - Day 2
Node.js Express Framework
01 Php Introduction
POCO C++ Libraries Intro and Overview
4.2 PHP Function
Php basics
Method overloading
Quick flask an intro to flask
JavaScript Promises
Javascript Design Patterns
Php string function
Test Driven Development with PHPUnit
React + Redux Introduction
Object oriented programming concepts
Ad

Similar to Advanced PHPUnit Testing (20)

PPT
Testing persistence in PHP with DbUnit
PPT
PHP Unit Testing
KEY
PHPUnit testing to Zend_Test
PDF
Introduction to Unit Testing with PHPUnit
PPT
course slides -- powerpoint
PPT
Automated Unit Testing
PPT
P H P Part I I, By Kian
PPT
Test driven development_for_php
KEY
Workshop quality assurance for php projects tek12
PDF
Workshop quality assurance for php projects - ZendCon 2013
PDF
Workshop quality assurance for php projects - phpbelfast
PPT
Bioinformatica 10-11-2011-p6-bioperl
PDF
Quality Assurance for PHP projects - ZendCon 2012
ODP
vfsStream - effective filesystem mocking
PDF
Fighting Fear-Driven-Development With PHPUnit
KEY
Unit testing with zend framework PHPBenelux
PDF
Unit testing with zend framework tek11
PPT
Core Php Component Presentation
PPT
Corephpcomponentpresentation 1211425966721657-8
KEY
Unit testing zend framework apps
Testing persistence in PHP with DbUnit
PHP Unit Testing
PHPUnit testing to Zend_Test
Introduction to Unit Testing with PHPUnit
course slides -- powerpoint
Automated Unit Testing
P H P Part I I, By Kian
Test driven development_for_php
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects - ZendCon 2013
Workshop quality assurance for php projects - phpbelfast
Bioinformatica 10-11-2011-p6-bioperl
Quality Assurance for PHP projects - ZendCon 2012
vfsStream - effective filesystem mocking
Fighting Fear-Driven-Development With PHPUnit
Unit testing with zend framework PHPBenelux
Unit testing with zend framework tek11
Core Php Component Presentation
Corephpcomponentpresentation 1211425966721657-8
Unit testing zend framework apps
Ad

Recently uploaded (20)

DOCX
unit 1 COST ACCOUNTING AND COST SHEET
PDF
Deliverable file - Regulatory guideline analysis.pdf
PPTX
ICG2025_ICG 6th steering committee 30-8-24.pptx
PDF
IFRS Notes in your pocket for study all the time
PPTX
HR Introduction Slide (1).pptx on hr intro
PDF
SIMNET Inc – 2023’s Most Trusted IT Services & Solution Provider
DOCX
unit 2 cost accounting- Tender and Quotation & Reconciliation Statement
PDF
Business model innovation report 2022.pdf
PPTX
Amazon (Business Studies) management studies
PDF
MSPs in 10 Words - Created by US MSP Network
PDF
How to Get Funding for Your Trucking Business
PDF
Laughter Yoga Basic Learning Workshop Manual
PDF
WRN_Investor_Presentation_August 2025.pdf
PPTX
CkgxkgxydkydyldylydlydyldlyddolydyoyyU2.pptx
DOCX
Euro SEO Services 1st 3 General Updates.docx
PPTX
job Avenue by vinith.pptxvnbvnvnvbnvbnbmnbmbh
PPT
Chapter four Project-Preparation material
PPTX
Lecture (1)-Introduction.pptx business communication
PDF
Training And Development of Employee .pdf
PPT
Data mining for business intelligence ch04 sharda
unit 1 COST ACCOUNTING AND COST SHEET
Deliverable file - Regulatory guideline analysis.pdf
ICG2025_ICG 6th steering committee 30-8-24.pptx
IFRS Notes in your pocket for study all the time
HR Introduction Slide (1).pptx on hr intro
SIMNET Inc – 2023’s Most Trusted IT Services & Solution Provider
unit 2 cost accounting- Tender and Quotation & Reconciliation Statement
Business model innovation report 2022.pdf
Amazon (Business Studies) management studies
MSPs in 10 Words - Created by US MSP Network
How to Get Funding for Your Trucking Business
Laughter Yoga Basic Learning Workshop Manual
WRN_Investor_Presentation_August 2025.pdf
CkgxkgxydkydyldylydlydyldlyddolydyoyyU2.pptx
Euro SEO Services 1st 3 General Updates.docx
job Avenue by vinith.pptxvnbvnvnvbnvbnbmnbmbh
Chapter four Project-Preparation material
Lecture (1)-Introduction.pptx business communication
Training And Development of Employee .pdf
Data mining for business intelligence ch04 sharda

Advanced PHPUnit Testing

  • 1. Advanced PHP Unit Testing The 2008 DC PHP Conference June 2nd, 2008
  • 2. Hello! Mike Lively Lead Developer Selling Source, Inc. PHPUnit Contributor PHPUnit Database Extension A frequent inhabitant of #phpc http://digitalsandwich.com
  • 3. PHPUnit A widely used unit testing framework Created by Sebastian Bergmann Originally built as a port of Junit Now incredibly feature rich
  • 4. PHPUnit - Advanced Features Mock Objects - A way to further isolate code while testing. Database Extension - A DBUnit port to allow creation of fixtures for database content. Selenium Integration - A gateway to integration testing. PHPUnderControl - Not really PHPUnit...but still very cool. Much to cover and not much of time. Let's get started!
  • 5. PHPUnit - Mock Objects Mock Objects - A way to further isolate code while testing. Creates 'Fake' objects that mimic 'real' objects in controlled ways. Used to ensure that expected methods are being called in expected ways. Used to ensure that methods that are depended on by the unit you are testing do not 'pollute' your test with their behavior.
  • 6. PHPUnit - Mock Objects How do I ensure a method is called properly?
  • 7. PHPUnit - Mock Objects How do I ensure a method is called properly? Create a mock object! PHPUnit_Framework_TestCase::getMock(   string $className,   array $methods = array(),   array $constructParms = array(),   string $mockClassName = '',   bool $callOriginalConstruct = TRUE,   bool $callOriginalClone = TRUE,   bool $callAutoLoad = TRUE );
  • 8. PHPUnit - Mock Objects Create the mock object <?php require_once  'PHPUnit/Framework.php' ;   class  ObserverTest  extends  PHPUnit_Framework_TestCase {     public function  testUpdateIsCalledOnce ()     {         $observer  =  $this -> getMock ( 'Observer' , array( 'update' ));     } } ?>
  • 9. PHPUnit - Mock Objects Setup the expectation <?php require_once  'PHPUnit/Framework.php' ;   class  ObserverTest  extends  PHPUnit_Framework_TestCase {     public function  testUpdateIsCalledOnce ()     {         $observer  =  $this -> getMock ( 'Observer' , array( 'update' ));          $observer -> expects ( $this -> once ())                  -> method ( 'update' )                  -> with ( $this -> equalTo ( 'something' ));     } } ?>
  • 10. PHPUnit - Mock Objects expects() - Sets how many times you expect a method to be called: any()‏ never()‏ atLeastOnce()‏ once()‏ exactly($count)‏ at($index) method() - The name of the method you are setting the expectation for
  • 11. PHPUnit - Mock Objects with() - Each parameter is validated using PHPUnit Constraints: anything()‏ contains($value)‏ arrayHasKey($key)‏ equalTo($value, $delta, $maxDepth)‏ classHasAttribute($attribute)‏ greaterThan($value)‏ isInstanceOf($className)‏ isType($type)‏ matchesRegularExpression($regex)‏ stringContains($string, $case) withAnyParameters() - A quick way to say &quot;I don't care&quot;
  • 12. PHPUnit - Mock Objects Call the tested code <?php require_once  'PHPUnit/Framework.php' ;   class  ObserverTest  extends  PHPUnit_Framework_TestCase {     public function  testUpdateIsCalledOnce ()     {         $observer  =  $this -> getMock ( 'Observer' , array( 'update' ));          $observer -> expects ( $this -> once ())                  -> method ( 'update' )                  -> with ( $this -> equalTo ( 'something' ));         $subject  = new  Subject ;          $subject -> attach ( $observer );           $subject -> doSomething ();     } } ?>
  • 13. PHPUnit - Mock Objects Force methods not being tested to return particular values. will() - Force the current method to return a particular value returnValue($value) - Returns the specified value throwException($exception) - Throws the specified exception object onConsecutiveCalls(...) - Performs each action (return or exception) consecutively.
  • 14. PHPUnit - Mock Objects Forcing methods to return certain values <?php require_once  'PHPUnit/Framework.php' ;   class  StubTest  extends  PHPUnit_Framework_TestCase {     public function  testStub ()     {          $stub  =  $this -> getMock ( 'SomeClass' , array( 'doSomething' ));          $stub -> expects ( $this -> any ())              -> method ( 'doSomething' )              -> will ( $this -> returnValue ( 'foo' ));            // Calling $stub->doSomething() will now return 'foo'.      } } ?>
  • 15. PHPUnit - Database Extension The PHPUnit Database Extension
  • 16. PHPUnit - Database Extension PHPUnit Database Extension - DBUnit Port Uses many of the same concepts Dataset formats are essentially identical Puts your database into a known state prior to testing Allows for setting expectations of data in your database at the end of a test
  • 17. PHPUnit - Database Extension PHPUnit_Extensions_Database_TestCase Overloads setUp() and tearDown() and introduces four new overridable methods (2 MUST be overriden) If implementing setUp or tearDown, please be sure to call parent::setUp() and parent::tearDown()‏
  • 18. PHPUnit - Database Extension Must implement getConnection() - Returns a database connection wrapper getDataSet() - Returns the dataset to seed the test database with. Can override getSetUpOperation() - Returns the operation used to set up the database (defaults to CLEAN_INSERT) getTearDownOperation() - Returns the operation to used to tear down the database (defaults to NONE)‏
  • 19. PHPUnit - Database Extension getConnection() returns a customized wrapper around a database connection. Current implementation uses PDO This does not mean code you are testing has to use PDO createDefaultDBConnection(   PDO $pdo,   string $schema ); // Convenience method Very important to provide the schema name.
  • 20. PHPUnit - Database Extension Setting up your database test case connection <?php require_once  'PHPUnit/Extensions/Database/TestCase.php' ;   class  DatabaseTest  extends  PHPUnit_Extensions_Database_TestCase {     protected function  getConnection ()     {          $pdo  = new  PDO ( 'mysql:host=localhost;dbname=testdb' ,  'root' ,  '' );         return  $this -> createDefaultDBConnection ( $pdo ,  'testdb' );     } } ?>
  • 21. PHPUnit - Database Extension Currently (known) supported databases: MySQL SQLite Postgres OCI8 Need another RDBMS supported? I NEED YOU!!!
  • 22. PHPUnit - Database Extension getDataSet() returns one of the following types of data sets: Flat XML XML Database Default (php array basically) Can be a pain to create Working on utilities to make it...less painful
  • 23. PHPUnit - Database Extension Convenience methods for datasets $this->createFlatXMLDataSet($xmlFile); $this->createXMLDataSet($xmlFile); Use full paths
  • 24. PHPUnit - Database Extension Setting up your database test case's common fixture <?php require_once  'PHPUnit/Extensions/Database/TestCase.php' ;   class  DatabaseTest  extends  PHPUnit_Extensions_Database_TestCase {     protected function  getConnection ()     {          $pdo  = new  PDO ( 'mysql:host=localhost;dbname=testdb' ,  'root' ,  '' );         return  $this -> createDefaultDBConnection ( $pdo ,  'testdb' );     }       protected function  getDataSet ()     {         return  $this -> createFlatXMLDataSet ( dirname ( __FILE__ ). '/_files/bank-account-seed.xml' );     } } ?>
  • 25. PHPUnit - Flat XML Data Set Each element represents a row, each attribute represents a column. All attributes must be present in the first element for a given table. Specifying an element with no attributes represents an empty table. If an attribute specified in the first element is missing in subsequent element, NULL is implied. There is no explicit NULL
  • 26. PHPUnit - Database Extension Flat XML <dataset>      <TEST_TABLE COL0=&quot;row 0 col 0&quot;          COL1=&quot;row 0 col 1&quot;          COL2=&quot;row 0 col 2&quot;/>      <TEST_TABLE COL1=&quot;row 1 col 1&quot;/>      <SECOND_TABLE COL0=&quot;row 0 col 0&quot;          COL1=&quot;row 0 col 1&quot; />      <EMPTY_TABLE/> </dataset>
  • 27. PHPUnit - XML Data Set A more robust and capable format <table> element for each table <column> element for each column <row> element for each row <row> will contain equal number of children as there are <column>s in the same order. <value>val</value> is used to specify a value <null/> used to explicitly specify NULL
  • 28. PHPUnit - Database Extension XML (Not so flat)‏ <dataset>     <table name=&quot;TEST_TABLE&quot;>         <column>COL0</column>         <column>COL1</column>         <column>COL2</column>         <row>             <value>row 0 col 0</value>             <value>row 0 col 1</value>             <value>row 0 col 2</value>         </row>         <row>             <null/>             <value>row 1 col 1</value>             <null/>         </row>     </table>     <table name='EMPTY_TABLE'>         <column>COLUMN0</column>         <column>COLUMN1</column>     </table> </dataset>
  • 29. PHPUnit - Other Data Sets Pull your data sets out of a database Possible, and might be a good way to do it for smaller database test suites. Wouldn't recommend it for large ones (yet) What about the Default data set? I haven't hated myself enough to bother with it yet :P Future formats? CSV, Composite Data Sets, Query Sets
  • 30. PHPUnit - Other Data Sets Pull your data sets out of a database Possible, and might be a good way to do it for smaller database test suites. Wouldn't recommend it for large ones (yet) What about the Default data set? I haven't hated myself enough to bother with it yet :P Future formats? CSV, Composite Data Sets, Query Sets <- this is when you'll want to use database data sets for large suites
  • 31. PHPUnit - Operations If you want to specify non-default operations override either getSetUpOperation() or getTearDownOperation() with a static method from the class: PHPUnit_Extensions_Database_Operation_Factory  NONE CLEAN_INSERT INSERT TRUNCATE DELETE DELETE_ALL UPDATE
  • 32. PHPUnit - Operations <?php require_once  'PHPUnit/Extensions/Database/TestCase.php' ;   class  DatabaseTest  extends  PHPUnit_Extensions_Database_TestCase {     protected function  getSetUpOperation ()     {         return  PHPUnit_Extensions_Database_Operation_Factory :: CLEAN_INSERT ();     }       protected function  getTearDownOperation ()     {         return  PHPUnit_Extensions_Database_Operation_Factory :: NONE ();     } } ?>
  • 33. PHPUnit - Database Extension Setting up database expectations. Retrieve database contents: $this->getConnection()->createDataSet(); Creates a dataset with ALL data in your database. Pass an array of table names if you only want to compare particular tables. You can also use the data set filter if necessary
  • 34. PHPUnit - Database Extension Why Filtered Data Sets? auto increment, time stamps PHPUnit_Extensions_Database_DataSet_DataSetFilter decorator Accepts existing dataset object as first parameter Accepts associative array as second parameter The array indexes are table names The array values are arrays of column names to exclude from the data set or the string '*' if the whole table is to be excluded.
  • 35. PHPUnit - Database Extension Refreshing our memory <?php require_once  'PHPUnit/Extensions/Database/TestCase.php' ;   class  DatabaseTest  extends  PHPUnit_Extensions_Database_TestCase {     protected function  getConnection ()     {          $pdo  = new  PDO ( 'mysql:host=localhost;dbname=testdb' ,  'root' ,  '' );         return  $this -> createDefaultDBConnection ( $pdo ,  'testdb' );     }       protected function  getDataSet ()     {         return  $this -> createFlatXMLDataSet ( dirname ( __FILE__ ). '/_files/bank-account-seed.xml' );     } } ?>
  • 36. PHPUnit - Database Extension Writing a test <?php require_once  'PHPUnit/Extensions/Database/TestCase.php' ;   class  DatabaseTest  extends  PHPUnit_Extensions_Database_TestCase {     // ...     public function  testAccountBalanceDeposits ()     {          $bank_account  = new  BankAccount ( '15934903649620486' ,  $this -> pdo );          $bank_account -> depositMoney ( 100 );               $bank_account  = new  BankAccount ( '15936487230215067' ,  $this -> pdo );          $bank_account -> depositMoney ( 230 );                   $bank_account  = new  BankAccount ( '12348612357236185' ,  $this -> pdo );          $bank_account -> depositMoney ( 24 );                    $xml_dataset  =  $this -> createFlatXMLDataSet ( dirname ( __FILE__ ). '/_files/bank-account-after-deposits.xml' );          $database_dataset = $this -> getConnection ()-> createDataSet ( array ( 'bank_account' ));     }     // ... } ?>
  • 37. PHPUnit - Database Extension Filtering out date_created <?php require_once  'PHPUnit/Extensions/Database/TestCase.php' ;   class  DatabaseTest  extends  PHPUnit_Extensions_Database_TestCase {     // ...     public function  testAccountBalanceDeposits ()     {         // ...                   $xml_dataset  =  $this -> createFlatXMLDataSet ( dirname ( __FILE__ ). '/_files/bank-account-after-deposits.xml' ); $database_dataset = new PHPUnit_Extensions_Database_DataSet_DataSetFilter ( $this -> getConnection ()-> createDataSet ( array ( 'bank_account' )), array ( 'bank_account' => array ( 'date_created' )) ); }     // ... } ?>
  • 38. PHPUnit - Database Extension $this->assertDataSetsEqual($expected, $actual) Compares all tables in the two data sets Must have equal and matching tables with equal and matching data Have I mentioned filters? $this->assertTablesEqual($expected, $actual) There is also a table filter!
  • 39. PHPUnit - Database Extension Writing a test <?php require_once  'PHPUnit/Extensions/Database/TestCase.php' ;   class  DatabaseTest  extends  PHPUnit_Extensions_Database_TestCase {     // ...     public function  testAccountBalanceDeposits ()     {          $bank_account  = new  BankAccount ( '15934903649620486' ,  $this -> pdo );          $bank_account -> depositMoney ( 100 );               $bank_account  = new  BankAccount ( '15936487230215067' ,  $this -> pdo );          $bank_account -> depositMoney ( 230 );                   $bank_account  = new  BankAccount ( '12348612357236185' ,  $this -> pdo );          $bank_account -> depositMoney ( 24 );                    $xml_dataset  =  $this -> createFlatXMLDataSet ( dirname ( __FILE__ ) . '/_files/bank-account-after-deposits.xml' ); $this -> assertDataSetsEqual ( $xml_dataset ,           $this -> getConnection ()-> createDataSet ( array ( 'bank_account' )) );     }     // ... } ?>
  • 40. PHPUnit - Selenium Selenium is a testing framework for web applications. Runs tests by controlling a remote browser session Can inspect the dom, look for events, and much much more Selenium tests can be made a part of your PHPUnit Test Suite
  • 41. PHPUnit - Selenium Selenium is a testing framework for web applications. Runs tests by controlling a remote browser session Can inspect the dom, look for events, and much much more Selenium tests can be made a part of your PHPUnit Test Suite
  • 42. PHPUnit - Selenium Demo Time!
  • 43. PHPUnit - Continuous Integration Continuous Integration is a software development practice where members of a team integrate their work frequently, usually each person integrates at least daily, leading to multiple integrations per day. Each integration is verified by an automated build (including test) to detect integration errors as quickly as possible. Many teams find that this approach leads to significantly reduced integration problems and allows a team to develop cohesive software more rapidly. -- Martin Fowler
  • 44. PHPUnit - PHPUnderControl Created and maintained by Manuel Pischler Cruise Control for the php developer Runs your Unit Tests Builds your documentation Lint checks your code Gives you build and performance metrics The best thing since sliced bread
  • 46. Thank you - Resources PHPUnit: http://phpun.it, http://planet.phpunit.de Selenium: http://selenium.openqa.org/ PHPUnderControl: http://www.phpundercontrol.org/ My Site: http://www.digitalsandwich.com My Employer's Site: http://dev.sellingsource.com Questions??