0
Introduction to Unit Testing with PHPUnit
           by Michelangelo van Dam
Contents
✓Who am I ?                  ✓Expected Exceptions
✓What is Unit                ✓Fixtures
Testing ?               ...
Who am I ?
Michelangelo van Dam

Independent Enterprise PHP consultant
Co-founder PHPBelgium

Mail me at dragonbe [at] gma...
What is Unit Testing ?


Wikipedia: “is a method of testing that verifies
the individual units of source code are working
p...
Unit Testing in short
•   unit: the smallest testable code of an app
    -   procedural: function or procedure
    -   OOP...
Why do (Unit) Testing ?

•   automated testing
•   test code on functionality
•   detect issues that break existing code
•...
SimpleTest

•   comparable to JUnit/PHPUnit
•   created by Marcus Baker
•   popular for testing web pages at browser
    l...
PHPUnit

•   Part of xUnit familiy (JUnit, SUnit,...)
•   created by Sebastian Bergmann
•   integrated/supported
    -   Z...
Starting with PHPUnit
Installation is done with the PEAR installer

# pear channel-discover pear.phpunit.de
# pear install...
Hello World
<?php
class HelloWorld
{
    public $helloWorld;

    public function __construct($string = ‘Hello World!’)
  ...
<?php
       Test HelloWorld class
require_once 'HelloWorld.php';
require_once 'PHPUnit/Framework.php';

class HelloWorldT...
Testing HelloWorld

# phpunit HelloWorldTest HelloWorldTest.php
PHPUnit 3.3.2 by Sebastian Bergmann.

..

Time: 0 seconds
...
More testing

•   data providers (@dataProvider)
•   exception (@expectedException)
•   fixtures (setUp() and tearDown())
•...
Data Provider

•   provides arbitrary arguments
    -   array
    -   object (that implements Iterator)
•   annotated by @...
CombineTest
<?php
class CombineTest extends PHPUnit_Framework_TestCase
{
    /**
      * @dataProvider provider
      */
 ...
Testing CombineTest
# phpunit CombineTest CombineTest.php
PHPUnit 3.3.2 by Sebastian Bergmann.

..F

Time: 0 seconds

Ther...
Expected Exception

•   testing exceptions
    -   that they are thrown
    -   are properly catched




                 ...
OopsTest
<?php
class OopsTest extends PHPUnit_Framework_TestCase
{
    public function testOops()
    {
        try {
    ...
Testing OopsTest

# phpunit OopsTest OopsTest.php
PHPUnit 3.3.2 by Sebastian Bergmann.

.

Time: 0 seconds

OK (1 test, 0 ...
Fixtures

•   is a “known state” of an application
    -   needs to be ‘set up’ at start of test
    -   needs to be ‘torn...
FixmeTest
<?php
class FixmeTest extends PHPUnit_Framework_TestCase
{
    protected $fixme;

    public function setUp()
  ...
Testing FixmeTest

# phpunit FixmeTest FixmeTest.php
PHPUnit 3.3.2 by Sebastian Bergmann.

..

Time: 0 seconds

OK (2 test...
Doubles


•   stub objects
•   mock objects




                   23
Stubs

•   isolates tests from external influences
    -   slow connections
    -   expensive and complex resources
•   rep...
StubTest
<?php
// example taken from phpunit.de
class StubTest extends PHPUnit_Framework_TestCase
{
    public function te...
Testing StubTest

# phpunit StubTest StubTest.php
PHPUnit 3.3.2 by Sebastian Bergmann.

.

Time: 0 seconds

OK (1 test, 1 ...
Mocks

•   simulated objects
•   mimics API or behaviour
•   in a controlled way
•   to test a real object




           ...
ObserverTest
<?php
// example taken from Sebastian Bergmann’s slides on
// slideshare.net/sebastian_bergmann/advanced-phpu...
Database Testing
•   Ported by Mike Lively from DBUnit
•   PHPUnit_Extensions_Database_TestCase
•   for database-driven pr...
BankAccount Example
                             BankAccount example by Mike Lively
               http://www.ds-o.com/arc...
BankAccount
<?php
require_once 'BankAccountException.php';

class BankAccount
{
    private $balance = 0;

   public funct...
BankAccount (2)
    ...

    public function depositMoney($balance)
    {
        $this->setBalance($this->getBalance() + ...
<?php
                BankAccountTest
require_once 'PHPUnit/Extensions/Database/TestCase.php';
require_once 'BankAccount.p...
BankAccountTest (2)

    ...

    public function testNewAccountCreation()
    {
        $bank_account = new BankAccount('...
Testing BankAccount
# phpunit BankAccountDbTest BankAccountDbTest.php PHPUnit 3.3.2 by
Sebastian Bergmann.

F

Time: 0 sec...
Testing BA (2)
...
1) testNewAccountCreation(BankAccountDBTest)
Failed asserting that actual
+----------------------+-----...
...
                Testing BA (3)
is equal to expected
+----------------------+----------------------+
| bank_account    ...
BankAccount Dataset

<!-- file: BankAccounts.xml -->
<dataset>
    <bank_account account_number=quot;15934903649620486quot...
Testing MVC ZF apps

•   Available from Zend Framework 1.6
•   Using Zend_Test
    http://framework.zend.com/manual/en/zen...
Hints & Tips
•   Make sure auto loading is set up
    -   your tests might fail on not finding classes
•   Move bootstrap t...
Defining the bootstrap
/**
  * default way to approach the bootstrap
  */
class IndexControllerTest extends Zend_Test_PHPUn...
Testing homepage

class IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
    // ...

    public function...
Testing GET params
class IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
    // ...

    public functio...
Testing POST params
class IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
    // ...

    public functi...
Testing COOKIE params
class IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
    // ...

    public func...
Let’s dispatch it
class IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
    // ...

    public function...
Demo

•   Using Zend Framework “QuickStart” app
    http://framework.zend.com/docs/quickstart


    -   modified with
     ...
Interesting Readings
•   PHPUnit by Sebastian Bergmann
    http://phpunit.de


•   Art of Unit Testing by Roy Osherove
   ...
Questions ?


              Thank you.
This presentation will be available on
  http://slideshare.com/DragonBe




       ...
Upcoming SlideShare
Loading in...5
×

Introduction to Unit Testing with PHPUnit

26,653

Published on

Introduction to Unit Testing with PHPUnit, added with the Zend Framework Test component.

Published in: Technology
3 Comments
23 Likes
Statistics
Notes
  • how to install pear without zend framework or i can use another framework?
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Also can u explain me some queries related to Database implementation class

    1. What is the state Database when we are testing this class
    Do the table contains the three record at the time of testing?
    Does the XML 'BankAccount.xml' and 'NewBankAccount.xml' are genrated dynamically ?
    Also what is the state of both the files before testing?

    Also when i test i do no get any new data inserted in DB
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Is it necessary to extend class with PPUnit_Extensions_Database_TestCase ?

    Can i get an example Without extending it ?
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total Views
26,653
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
584
Comments
3
Likes
23
Embeds 0
No embeds

No notes for slide

Transcript of "Introduction to Unit Testing with PHPUnit"

  1. 1. Introduction to Unit Testing with PHPUnit by Michelangelo van Dam
  2. 2. Contents ✓Who am I ? ✓Expected Exceptions ✓What is Unit ✓Fixtures Testing ? ✓Doubles ✓Unit Testing in short ✓Stubs ✓Why do Testing ? ✓Mocks ✓SimpleTest ✓Database Testing ✓PHPUnit ✓Zend_Test ✓Starting w/ PHPUnit ✓Interesting Readings ✓Example ✓Questions ? ✓More Testing ✓Data Provider 2
  3. 3. Who am I ? Michelangelo van Dam Independent Enterprise PHP consultant Co-founder PHPBelgium Mail me at dragonbe [at] gmail [dot] com Follow me on http://twitter.com/DragonBe Read my articles on http://dragonbe.com See my profile on http://linkedin.com/in/michelangelovandam 3
  4. 4. What is Unit Testing ? Wikipedia: “is a method of testing that verifies the individual units of source code are working properly” 4
  5. 5. Unit Testing in short • unit: the smallest testable code of an app - procedural: function or procedure - OOP: a method • test: code that checks code on - functional behavior ✓ expected results ✓ unexpected failures 5
  6. 6. Why do (Unit) Testing ? • automated testing • test code on functionality • detect issues that break existing code • progress indication of the project • alerts generation for monitoring tools 6
  7. 7. SimpleTest • comparable to JUnit/PHPUnit • created by Marcus Baker • popular for testing web pages at browser level 7
  8. 8. PHPUnit • Part of xUnit familiy (JUnit, SUnit,...) • created by Sebastian Bergmann • integrated/supported - Zend Studio - Zend Framework 8
  9. 9. Starting with PHPUnit Installation is done with the PEAR installer # pear channel-discover pear.phpunit.de # pear install phpunit/PHPUnit Upgrading is as simple # pear upgrade phpunit/PHPUnit 9
  10. 10. Hello World <?php class HelloWorld { public $helloWorld; public function __construct($string = ‘Hello World!’) { $this->helloWorld = $string; } public function sayHello() { return $this->helloWorld; } } 10
  11. 11. <?php Test HelloWorld class require_once 'HelloWorld.php'; require_once 'PHPUnit/Framework.php'; class HelloWorldTest extends PHPUnit_Framework_TestCase { public function test__construct() { $hw = new HelloWorld(); $this->assertType('HelloWorld', $hw); } public function testSayHello() { $hw = new HelloWorld(); $string = $hw->sayHello(); $this->assertEquals('Hello World!', $string); } } 11
  12. 12. Testing HelloWorld # phpunit HelloWorldTest HelloWorldTest.php PHPUnit 3.3.2 by Sebastian Bergmann. .. Time: 0 seconds OK (2 tests, 2 assertions) 12
  13. 13. More testing • data providers (@dataProvider) • exception (@expectedException) • fixtures (setUp() and tearDown()) • doubles (mocks and stubs) • database testing 13
  14. 14. Data Provider • provides arbitrary arguments - array - object (that implements Iterator) • annotated by @dataProvider provider • multiple arguments 14
  15. 15. CombineTest <?php class CombineTest extends PHPUnit_Framework_TestCase { /** * @dataProvider provider */ public function testCombine($a, $b, $c) { $this->assertEquals($c, $a . ' ' . $b); } public function provider() { return array ( array ('Hello','World','Hello World'), array ('Go','PHP','Go PHP'), array ('This','Fails','This succeeds') ); } } 15
  16. 16. Testing CombineTest # phpunit CombineTest CombineTest.php PHPUnit 3.3.2 by Sebastian Bergmann. ..F Time: 0 seconds There was 1 failure: 1) testCombine(CombineTest) with data set #2 ('This', 'Fails', 'This succeeds') Failed asserting that two strings are equal. expected string <This succeeds> difference < xxxxx???> got string <This Fails> /root/dev/phpunittutorial/CombineTest.php:9 FAILURES! Tests: 3, Assertions: 3, Failures: 1. 16
  17. 17. Expected Exception • testing exceptions - that they are thrown - are properly catched 17
  18. 18. OopsTest <?php class OopsTest extends PHPUnit_Framework_TestCase { public function testOops() { try { throw new Exception('I just made a booboo'); } catch (Exception $expected) { return; } $this->fail('An expected Exception was not thrown'); } } 18
  19. 19. Testing OopsTest # phpunit OopsTest OopsTest.php PHPUnit 3.3.2 by Sebastian Bergmann. . Time: 0 seconds OK (1 test, 0 assertions) 19
  20. 20. Fixtures • is a “known state” of an application - needs to be ‘set up’ at start of test - needs to be ‘torn down’ at end of test - shares “states” over test methods 20
  21. 21. FixmeTest <?php class FixmeTest extends PHPUnit_Framework_TestCase { protected $fixme; public function setUp() { $this->fixme = array (); } public function testFixmeEmpty() { $this->assertEquals(0, sizeof($this->fixme)); } public function testFixmeHasOne() { array_push($this->fixme, 'element'); $this->assertEquals(1, sizeof($this->fixme)); } } 21
  22. 22. Testing FixmeTest # phpunit FixmeTest FixmeTest.php PHPUnit 3.3.2 by Sebastian Bergmann. .. Time: 0 seconds OK (2 tests, 2 assertions) 22
  23. 23. Doubles • stub objects • mock objects 23
  24. 24. Stubs • isolates tests from external influences - slow connections - expensive and complex resources • replaces a “system under test” (SUT) - for the purpose of testing 24
  25. 25. StubTest <?php // example taken from phpunit.de class StubTest extends PHPUnit_Framework_TestCase { public function testStub() { $stub = $this->getMock('SomeClass'); $stub->expects($this->any()) ->method('doSometing') ->will($this->returnValue('foo')); } // Calling $stub->doSomething() will now return 'foo' } 25
  26. 26. Testing StubTest # phpunit StubTest StubTest.php PHPUnit 3.3.2 by Sebastian Bergmann. . Time: 0 seconds OK (1 test, 1 assertion) 26
  27. 27. Mocks • simulated objects • mimics API or behaviour • in a controlled way • to test a real object 27
  28. 28. ObserverTest <?php // example taken from Sebastian Bergmann’s slides on // slideshare.net/sebastian_bergmann/advanced-phpunit-topics 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) ->doSomething(); } } 28
  29. 29. Database Testing • Ported by Mike Lively from DBUnit • PHPUnit_Extensions_Database_TestCase • for database-driven projects • puts DB in know state between tests • imports and exports DB data from/to XML • easily added to existing tests 29
  30. 30. BankAccount Example BankAccount example by Mike Lively http://www.ds-o.com/archives/63-PHPUnit-Database-Extension-DBUnit-Port.html http://www.ds-o.com/archives/64-Adding-Database-Tests-to-Existing-PHPUnit-Test-Cases.html BankAccount class by Sebastian Bergmann http://www.slideshare.net/sebastian_bergmann/testing-phpweb-applications-with-phpunit-and-selenium The full BankAccount class http://www.phpunit.de/browser/phpunit/branches/release/3.3/PHPUnit/Samples/BankAccount/BankAccount.php 30
  31. 31. BankAccount <?php require_once 'BankAccountException.php'; class BankAccount { private $balance = 0; public function getBalance() { return $this->balance; } public function setBalance($balance) { if ($balance >= 0) { $this->balance = $balance; } else { throw new BankAccountException; } } ... 31
  32. 32. BankAccount (2) ... public function depositMoney($balance) { $this->setBalance($this->getBalance() + $balance); return $this->getBalance(); } public function withdrawMoney($balance) { $this->setBalance($this->getBalance() - $balance); return $this->getBalance(); } } <?php class BankAccountException extends RuntimeException { } 32
  33. 33. <?php BankAccountTest require_once 'PHPUnit/Extensions/Database/TestCase.php'; require_once 'BankAccount.php'; class BankAccountDBTest extends PHPUnit_Extensions_Database_TestCase { protected $pdo; public function __construct() { $this->pdo = new PDO('sqlite::memory:'); BankAccount::createTable($this->pdo); } protected function getConnection() { return $this->createDefaultDBConnection($this->pdo, 'sqlite'); } protected function getDataSet() { return $this->createFlatXMLDataSet( dirname(__FILE__) . '/BankAccounts.xml'); } ... 33
  34. 34. BankAccountTest (2) ... public function testNewAccountCreation() { $bank_account = new BankAccount('12345678912345678', $this->pdo); $xml_dataset = $this->createFlatXMLDataSet( dirname(__FILE__) . '/NewBankAccounts.xml'); $this->assertDataSetsEqual( $xml_dataset, $this->getConnection()->createDataSet() ); } } 34
  35. 35. Testing BankAccount # phpunit BankAccountDbTest BankAccountDbTest.php PHPUnit 3.3.2 by Sebastian Bergmann. F Time: 0 seconds There was 1 failure: ... 35
  36. 36. Testing BA (2) ... 1) testNewAccountCreation(BankAccountDBTest) Failed asserting that actual +----------------------+----------------------+ | bank_account | +----------------------+----------------------+ | account_number | balance | +----------------------+----------------------+ | 12345678912345678 | 0 | +----------------------+----------------------+ | 12348612357236185 | 89 | +----------------------+----------------------+ | 15934903649620486 | 100 | +----------------------+----------------------+ | 15936487230215067 | 1216 | +----------------------+----------------------+ 36
  37. 37. ... Testing BA (3) is equal to expected +----------------------+----------------------+ | bank_account | +----------------------+----------------------+ | account_number | balance | +----------------------+----------------------+ | 15934903649620486 | 100.00 | +----------------------+----------------------+ | 15936487230215067 | 1216.00 | +----------------------+----------------------+ | 12348612357236185 | 89.00 | +----------------------+----------------------+ Reason: Expected row count of 3, has a row count of 4 /root/dev/phpunittutorial/BankAccountDbTest.php:33 FAILURES! Tests: 1, Assertions: 1, Failures: 1. 37
  38. 38. BankAccount Dataset <!-- file: BankAccounts.xml --> <dataset> <bank_account account_number=quot;15934903649620486quot; balance=quot;100.00quot; /> <bank_account account_number=quot;15936487230215067quot; balance=quot;1216.00quot; /> <bank_account account_number=quot;12348612357236185quot; balance=quot;89.00quot; /> </dataset> 38
  39. 39. Testing MVC ZF apps • Available from Zend Framework 1.6 • Using Zend_Test http://framework.zend.com/manual/en/zend.test.html • Requests and Responses are mocked 39
  40. 40. Hints & Tips • Make sure auto loading is set up - your tests might fail on not finding classes • Move bootstrap to a plugin - allows to PHP callback the bootstrap - allows to specify environment succinctly - allows to bootstrap application in a 1 line 40
  41. 41. Defining the bootstrap /** * default way to approach the bootstrap */ class IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase { public $bootstrap = '/path/to/bootstrap.php'; // ... } /** * Using PHP callback */ class IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase { public $bootstrap = array('App', 'bootstrap'); // ... } 41
  42. 42. Testing homepage class IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase { // ... public function testHomePage() { $this->dispatch('/'); // ... } } 42
  43. 43. Testing GET params class IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase { // ... public function testGetActionShouldReceiveGetParams() { // Set GET variables: $this->request->setQuery(array( 'foo' => 'bar', 'bar' => 'baz', )); } // ... } 43
  44. 44. Testing POST params class IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase { // ... public function testPostActionShouldReceivePostParams() { // Set POST variables: $this->request->setPost(array( 'foo' => 'bar', 'bar' => 'baz', )); } // ... } 44
  45. 45. Testing COOKIE params class IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase { // ... public function testCookieActionShouldReceiveCookieParams() { // First set a cookie value $this->request->setCookie('username', 'DragonBe'); // Or set multiple cookies at once $this->request->setCookies(array( 'last_seen' => time(), 'userlevel' => 'Admin', )); } // ... } 45
  46. 46. Let’s dispatch it class IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase { // ... public function testCookieActionShouldReceiveCookieParams() { // First set a cookie value $this->request->setCookie('username', 'DragonBe'); // Or set multiple cookies at once $this->request->setCookies(array( 'last_seen' => time(), 'userlevel' => 'Admin', )); // Let’s define the request method $this->request->setMethod('POST'); // Dispatch the homepage $this->dispatch('/'); } // ... } 46
  47. 47. Demo • Using Zend Framework “QuickStart” app http://framework.zend.com/docs/quickstart - modified with ✓ detail entry • Downloads provided on http://mvandam.com/demos/zftest.zip 47
  48. 48. Interesting Readings • PHPUnit by Sebastian Bergmann http://phpunit.de • Art of Unit Testing by Roy Osherove http://artofunittesting.com • Mike Lively’s blog http://www.ds-o.com/archives/63-PHPUnit-Database-Extension-DBUnit-Port.html • Zend Framework Manual: Zend_Test http://framework.zend.com/manual/en/zend.test.phpunit.html 48
  49. 49. Questions ? Thank you. This presentation will be available on http://slideshare.com/DragonBe 49
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×