SlideShare a Scribd company logo
PHPUnit and Zend Test
ZendCon 2009, San Jose, CA
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




                      2
Unit testing ?

•   test smallest piece of code (unit)
•   to verify its behavior is as expected
•   exceptions are thrown
•   code remains backwards compatible




                             3
Everyone should test !
•   rule #1: you should test
•   rule #2: see rule #1 (no excuses!!!)

•   Why?
    - tests are automated
    - run over and over again
    - detect flaws, errors, mistakes, screw ups
    - progress indication of the project
                              4
Why PHPUnit ?

•   part of xUnit family
•   ported by Sebastian Bergmann
•   PEAR package
    - pear channel-discover pear.phpunit.de
    - pear install phpunit/PHPUnit


                             5
PHPUnit !== Atlassian Jira


        Just making sure ;-)




                6
<?php
                  My first class
class SayHello
{
  public $name;

    public function __construct($name = 'nobody')
    {
      $this->name = $name;
    }

    public function speak()
    {
      return "Hello {$this->name}!";
    }
}




                                 7
<?php
                           Run it
require_once 'sayhello.php';

$hello = new SayHello();
echo $hello->speak();

// outputs Hello nobody!




                               8
<?php
                       Test it !
require_once 'sayhello.php';

class SayHelloTest extends PHPUnit_Framework_TestCase
{
    public function testSpeakWithoutParams ()
    {
        $hello = new SayHello();
        $this->assertEquals("Hello nobody!", $hello->speak());
    }

    public function testSpeakWithParams ()
    {
        $hello = new SayHello('Marco');
        $this->assertEquals("Hello Marco!", $hello->speak());
    }
}




                               9
We’re good
$ phpunit SayHelloTest
PHPUnit 3.3.15 by Sebastian Bergmann.

..

Time: 0 seconds

OK (2 tests, 2 assertions)




                               10
It’s that simple !




        11
Test Driven Development

•   think about functionality
•   think about testable functionality
•   write functional tests
•   write functionality




                              12
More testing

•   data providers (@dataProvider)
•   exception (@expectedException)
•   fixtures (setUp() and tearDown())
•   doubles (mocks and stubs)
•   database testing



                       13
Data Provider

•   provides arbitrary arguments
    -   array
    -   object (that implements Iterator)
•   annotated by @dataProvider provider
•   multiple arguments



                         14
<?php
                 CombineTest
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
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
Expected Exception

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




                         17
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
Testing OopsTest

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

.

Time: 0 seconds

OK (1 test, 0 assertions)




                                19
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
<?php
                     FixmeTest
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
Testing FixmeTest

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

..

Time: 0 seconds

OK (2 tests, 2 assertions)




                                22
Doubles


•   stub objects
•   mock objects




                   23
Stubs

•   isolates tests from external influences
    -   slow connections
    -   expensive and complex resources
•   replaces a “system under test” (SUT)
    -   for the purpose of testing



                         24
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
Testing StubTest

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

.

Time: 0 seconds

OK (1 test, 1 assertion)




                                26
Mocks

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




                          27
<?php
                ObserverTest
// 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
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
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 Classs 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/BankAccountDB/
                                        BankAccount.php




                                                30
Database Testing Example
<?php
require_once 'PHPUnit/Extensions/Database/Tescase.php';
require_once 'PHPUnit/Extensions/Database/Dataset/FlatXmlDataSet.php';
require_once 'BankAccount.php';

class BankAccountDBTest extends PHPUnit_Extensions_Database_Testcase
{
  public function getConnection()
  {
    $pdo = new PDO('sqlite::memory:');
    return $this->createDefaultDBConnection($pdo, 'testdb');
  }

  public function getDataSet()
  {
    return $this->createFlatFileXMLDataSet(
      dirname(__FILE__) . '/_files/dataset.xml');
  }
...




                                     31
Testing data store/retrieve
...

public function testNewAccountCreation()
{
  $bank_account = new BankAccount('12345678912345678', $this->pdo);
  $xml_dataset = $this->createFlatXMLDataSet(
    dirname(__FILE__).'/_files/ba-new-account.xml');
  $this->assertDataSetsEquals($xml_dataset,
    $this->getConnection()->createDataSet());
}

...




                               32
Testing BankAccount

$ phpunit BankAccountDBTestPHPUnit 3.3.15 by Sebastian Bergmann.

.....

Time: 0 seconds

OK (5 tests, 10 assertions)




                                33
BankAccount Dataset

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
    <bank_account account_number="15934903649620486" balance="100.00" />
    <bank_account account_number="15936487230215067" balance="1216.00" />
    <bank_account account_number="12348612357236185" balance="89.00" />
</dataset>




                                           34
Testing ZF App

•   using ZF bootstrap
•   uses ZF autoloading
•   tests MVC controllers and views




                         35
<?php
             Testing Controllers
require_once 'Zend/Test/PHPUnit/TestCase.php';

class IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
  public function setUp()
  {
    $this->bootstrap = array ($this, 'bootstrap');
    parent::setUp();
  }

    public function tearDown()
    {
      parent::tearDown();
      $this->bootstrap = null;
    }

    public function bootstrap()
    {
      $this->frontController->registerPlugin(new Initializer('test'));
    }

    // tests goes here
}


                                       36
Zend_Test_PHPUnit

•   Dispatching: $this->dispatch(‘/’);
•   Testing Controller:
    $this->assertController(‘index’);
•   Testing Action:
    $this->assertAction(‘index’);



                        37
More on Zend_Test
http://framework.zend.com/manual/en/zend.test.html

              Jon Lebensold’s ZendCast sessions
                   http://www.zendcast.com

    ZendCast on Zend Framework Unit Testing
    http://www.zendcasts.com/unit-testing-with-the-zend-framework-with-zend_test-and-phpunit/2009/06/




                                                38
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




                                      39
Credits
                     Thumbs up monkey
  http://www.flickr.com/photos/amberandclint/3266859324/

                     Lomo elePHPant
  http://www.flickr.com/photos/jakobwesthoff/3231273333/

                    Sebastian Bergmann
http://www.flickr.com/photos/sebastian_bergmann/2293021853



                          40
NOTICE


No elePHPants were harmed
while performing these tests




            41
License
This presentation is released under the Creative Commons
Attribution-Share Alike 3.0 Unported License
You are free:
- to share : to copy, distribute and transmit the work
- to remix : to adapt the work

Under the following conditions:
- attribution :You must attribute the work in the manner specified by the author or licensor
- share alike : If you alter, transform, or build upon this work, you may distribute the resulting work
only under the same, similar or a compatible license



See: http://creativecommons.org/licenses/by-sa/3.0/



                                                42
Questions ?

             Thank you

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

           Vote this talk
         http://joind.in/638



                 43

More Related Content

Php Unit With Zend Framework Zendcon09

  • 1. PHPUnit and Zend Test ZendCon 2009, San Jose, CA
  • 2. 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 2
  • 3. Unit testing ? • test smallest piece of code (unit) • to verify its behavior is as expected • exceptions are thrown • code remains backwards compatible 3
  • 4. Everyone should test ! • rule #1: you should test • rule #2: see rule #1 (no excuses!!!) • Why? - tests are automated - run over and over again - detect flaws, errors, mistakes, screw ups - progress indication of the project 4
  • 5. Why PHPUnit ? • part of xUnit family • ported by Sebastian Bergmann • PEAR package - pear channel-discover pear.phpunit.de - pear install phpunit/PHPUnit 5
  • 6. PHPUnit !== Atlassian Jira Just making sure ;-) 6
  • 7. <?php My first class class SayHello { public $name; public function __construct($name = 'nobody') { $this->name = $name; } public function speak() { return "Hello {$this->name}!"; } } 7
  • 8. <?php Run it require_once 'sayhello.php'; $hello = new SayHello(); echo $hello->speak(); // outputs Hello nobody! 8
  • 9. <?php Test it ! require_once 'sayhello.php'; class SayHelloTest extends PHPUnit_Framework_TestCase { public function testSpeakWithoutParams () { $hello = new SayHello(); $this->assertEquals("Hello nobody!", $hello->speak()); } public function testSpeakWithParams () { $hello = new SayHello('Marco'); $this->assertEquals("Hello Marco!", $hello->speak()); } } 9
  • 10. We’re good $ phpunit SayHelloTest PHPUnit 3.3.15 by Sebastian Bergmann. .. Time: 0 seconds OK (2 tests, 2 assertions) 10
  • 12. Test Driven Development • think about functionality • think about testable functionality • write functional tests • write functionality 12
  • 13. More testing • data providers (@dataProvider) • exception (@expectedException) • fixtures (setUp() and tearDown()) • doubles (mocks and stubs) • database testing 13
  • 14. Data Provider • provides arbitrary arguments - array - object (that implements Iterator) • annotated by @dataProvider provider • multiple arguments 14
  • 15. <?php CombineTest 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. 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. Expected Exception • testing exceptions - that they are thrown - are properly catched 17
  • 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. Testing OopsTest # phpunit OopsTest OopsTest.php PHPUnit 3.3.2 by Sebastian Bergmann. . Time: 0 seconds OK (1 test, 0 assertions) 19
  • 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. <?php FixmeTest 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. Testing FixmeTest # phpunit FixmeTest FixmeTest.php PHPUnit 3.3.2 by Sebastian Bergmann. .. Time: 0 seconds OK (2 tests, 2 assertions) 22
  • 23. Doubles • stub objects • mock objects 23
  • 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. 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. Testing StubTest # phpunit StubTest StubTest.php PHPUnit 3.3.2 by Sebastian Bergmann. . Time: 0 seconds OK (1 test, 1 assertion) 26
  • 27. Mocks • simulated objects • mimics API or behaviour • in a controlled way • to test a real object 27
  • 28. <?php ObserverTest // 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. 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. 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 Classs 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/BankAccountDB/ BankAccount.php 30
  • 31. Database Testing Example <?php require_once 'PHPUnit/Extensions/Database/Tescase.php'; require_once 'PHPUnit/Extensions/Database/Dataset/FlatXmlDataSet.php'; require_once 'BankAccount.php'; class BankAccountDBTest extends PHPUnit_Extensions_Database_Testcase { public function getConnection() { $pdo = new PDO('sqlite::memory:'); return $this->createDefaultDBConnection($pdo, 'testdb'); } public function getDataSet() { return $this->createFlatFileXMLDataSet( dirname(__FILE__) . '/_files/dataset.xml'); } ... 31
  • 32. Testing data store/retrieve ... public function testNewAccountCreation() { $bank_account = new BankAccount('12345678912345678', $this->pdo); $xml_dataset = $this->createFlatXMLDataSet( dirname(__FILE__).'/_files/ba-new-account.xml'); $this->assertDataSetsEquals($xml_dataset, $this->getConnection()->createDataSet()); } ... 32
  • 33. Testing BankAccount $ phpunit BankAccountDBTestPHPUnit 3.3.15 by Sebastian Bergmann. ..... Time: 0 seconds OK (5 tests, 10 assertions) 33
  • 34. BankAccount Dataset <?xml version="1.0" encoding="UTF-8"?> <dataset> <bank_account account_number="15934903649620486" balance="100.00" /> <bank_account account_number="15936487230215067" balance="1216.00" /> <bank_account account_number="12348612357236185" balance="89.00" /> </dataset> 34
  • 35. Testing ZF App • using ZF bootstrap • uses ZF autoloading • tests MVC controllers and views 35
  • 36. <?php Testing Controllers require_once 'Zend/Test/PHPUnit/TestCase.php'; class IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase { public function setUp() { $this->bootstrap = array ($this, 'bootstrap'); parent::setUp(); } public function tearDown() { parent::tearDown(); $this->bootstrap = null; } public function bootstrap() { $this->frontController->registerPlugin(new Initializer('test')); } // tests goes here } 36
  • 37. Zend_Test_PHPUnit • Dispatching: $this->dispatch(‘/’); • Testing Controller: $this->assertController(‘index’); • Testing Action: $this->assertAction(‘index’); 37
  • 38. More on Zend_Test http://framework.zend.com/manual/en/zend.test.html Jon Lebensold’s ZendCast sessions http://www.zendcast.com ZendCast on Zend Framework Unit Testing http://www.zendcasts.com/unit-testing-with-the-zend-framework-with-zend_test-and-phpunit/2009/06/ 38
  • 39. 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 39
  • 40. Credits Thumbs up monkey http://www.flickr.com/photos/amberandclint/3266859324/ Lomo elePHPant http://www.flickr.com/photos/jakobwesthoff/3231273333/ Sebastian Bergmann http://www.flickr.com/photos/sebastian_bergmann/2293021853 40
  • 41. NOTICE No elePHPants were harmed while performing these tests 41
  • 42. License This presentation is released under the Creative Commons Attribution-Share Alike 3.0 Unported License You are free: - to share : to copy, distribute and transmit the work - to remix : to adapt the work Under the following conditions: - attribution :You must attribute the work in the manner specified by the author or licensor - share alike : If you alter, transform, or build upon this work, you may distribute the resulting work only under the same, similar or a compatible license See: http://creativecommons.org/licenses/by-sa/3.0/ 42
  • 43. Questions ? Thank you This presentation will be available on http://slideshare.com/DragonBe Vote this talk http://joind.in/638 43