$30 off During Our Annual Pro Sale. View Details »

PHPUnit Workshop CCXX13

Joshua Thijssen
November 07, 2013
170

PHPUnit Workshop CCXX13

Joshua Thijssen

November 07, 2013
Tweet

Transcript

  1. TechAdemy.nl
    PHPUNIT
    An introduction into unit-testing with PHP

    View Slide

  2. TechAdemy.nl
    WELCOME!

    View Slide

  3. TechAdemy.nl
    Joshua Thijssen
    Freelance consultant, developer and
    trainer @ NoxLogic & TechAdemy
    Founder of the Dutch Web Alliance.
    Development in PHP, Python, C, Java.
    Lead developer of Saffire.
    Blog: http://adayinthelifeof.nl
    Email: [email protected]
    Twitter: @jaytaph

    View Slide

  4. TechAdemy.nl
    http://www.techademy.nl

    View Slide

  5. TechAdemy.nl

    View Slide

  6. TechAdemy.nl
    schedule
    • A mind-numbing and dreaded talk
    about unit-testing.
    • Hours and hours of trying to setup our
    systems for PHPUnit.
    • Spending ages on trying our first unit tests.
    • Never ever reaching the advanced stuff..

    View Slide

  7. TechAdemy.nl
    What is unit testing?

    View Slide

  8. TechAdemy.nl
    • Unit testing
    • Integration testing
    • Stress testing
    • Regression testing
    • Acceptance testing
    • A/B testing
    • Security testing
    • Usability testing
    Much more....

    View Slide

  9. TechAdemy.nl
    FooTest.php:
    Foo.php
    class foo
    {
    public function baz() {
    return 1;
    }
    }
    require “Foo.php”;
    class fooTest extends PHPUnit_Framework_TestCase
    {
    public function testBlahBlah() {
    $foo = new Foo();
    $this->assertEquals($foo->baz(), 1);
    }
    }

    View Slide

  10. TechAdemy.nl

    View Slide

  11. TechAdemy.nl FooTest.php:
    Foo.php
    class foo
    {
    public function baz() {
    return 1;
    }
    public function isOdd($number) {
    if (($number & 1) == 1) {
    return true;
    } else {
    return false;
    }
    }
    }
    include_once "Foo.php";
    class fooTest extends PHPUnit_Framework_TestCase
    {
    public function testBlahBlah() {
    $foo = new Foo();
    $this->assertEquals($foo->baz(), 1);
    }
    public function testIsOdd() {
    $foo = new Foo();
    $this->assertTrue($foo->isOdd(1));
    }
    }

    View Slide

  12. TechAdemy.nl

    View Slide

  13. TechAdemy.nl
    FooTest.php:
    include_once "foo.php";
    class fooTest extends PHPUnit_Framework_TestCase
    {
    public function testBlahBlah() {
    $foo = new Foo();
    $this->assertEquals($foo->baz(), 1);
    }
    public function testIsOdd() {
    $foo = new Foo();
    $this->assertTrue($foo->isOdd(1));
    }
    public function testDoesIsOddReturnFalseWhenAnEvenDigitIsGiven {
    $foo = new Foo();
    $this->assertFalse($foo->isOdd(2));
    }
    }

    View Slide

  14. TechAdemy.nl

    View Slide

  15. TechAdemy.nl
    This is it!
    You’re done!
    go home!
    really!

    View Slide

  16. TechAdemy.nl
    • Every test must be able to be executed
    separately and without dependencies.
    • Test “units”, not “applications”
    • MVC: controller tests, but these are not
    unit tests.
    • Be careful with external resources (DB,
    Mail, HTTP etc)

    View Slide

  17. TechAdemy.nl
    • Don’t strive for 100% code coverage.
    • Not important, and probably not
    realistically possible
    • High code coverage != great tests!
    • Code coverage the hotspots.

    View Slide

  18. TechAdemy.nl
    Why write unit-tests?

    View Slide

  19. TechAdemy.nl
    • Developers should code properly in the
    first place!
    • We don’t have time enough to do
    unittesting!
    • Tests keep failing. We can’t change our
    whole base!
    • Too much to test!

    View Slide

  20. TechAdemy.nl
    • writing tests increases coding time.
    • writing tests decreases debug time.
    • overall decreases development time.

    View Slide

  21. TechAdemy.nl
    • Is your code working as intended ?
    • Are old bugs not returned by accident
    (merges) ?
    • Are new bugs not introduced ?
    • Is your architecture flexible enough ?

    View Slide

  22. TechAdemy.nl
    phpunit advanced
    • setUp(), tearDown()
    • @depends
    • @dataproviders
    • @exception
    • mocking & stubbing

    View Slide

  23. TechAdemy.nl
    class fooTest extends PHPUnit_Framework_TestCase
    {
    public function testBlahBlah() {
    $foo = new Bar();
    ....
    }
    public function testBlah() {
    $foo = new Bar();
    ....
    }
    }

    View Slide

  24. TechAdemy.nl
    class fooTest extends PHPUnit_Framework_TestCase
    {
    public setUp() {
    $this->_foo = new Bar();
    }
    public tearDown() {
    unset($this->_foo);
    }
    public function testBlahBlah() {
    ....
    }
    public function testBlah() {
    ....
    }
    }

    View Slide

  25. TechAdemy.nl
    class fooTest extends PHPUnit_Framework_TestCase
    {
    public function testFoo() {
    ....
    }
    /**
    * @depends testFoo
    */
    public function testBar() {
    ....
    }
    }

    View Slide

  26. TechAdemy.nl
    Annotations have to be inside docblocks, not comments!
    comment = /* hello */
    docblock = /** hello */

    View Slide

  27. TechAdemy.nl
    class fooTest extends PHPUnit_Framework_TestCase
    {
    public function testCount() {
    $foo = new Foo();
    $this->assertEquals($foo->add(1, 2), 3);
    $this->assertEquals($foo->add(10,-4), 6);
    $this->assertEquals($foo->add(4, 6), 10);
    ...
    }
    }

    View Slide

  28. TechAdemy.nl
    class fooTest extends PHPUnit_Framework_TestCase
    {
    /**
    * @dataprovider countProvider
    */
    public function testCount($a, $b, $c) {
    $foo = new Foo();
    $this->assertEquals($foo->add($a, $b), $c);
    }
    public function countProvider() {
    return array(
    array(1, 2, 3),
    array(10, -4, 6),
    array(4, 6, 10)
    );
    }
    }

    View Slide

  29. TechAdemy.nl
    class fooTest extends PHPUnit_Framework_TestCase
    {
    public function testCount() {
    $foo = new Foo();
    try {
    $foo->functionWithException();
    $this->fail(“An exception should have occurred”);
    } catch (Exception $e) {
    }
    }
    }

    View Slide

  30. TechAdemy.nl
    class fooTest extends PHPUnit_Framework_TestCase
    {
    /**
    * @expectedException Exception
    */
    public function testCount() {
    $foo = new Foo();
    $foo->functionWithException();
    }
    }

    View Slide

  31. TechAdemy.nl
    class fooTest extends PHPUnit_Framework_TestCase
    {
    public function testCount() {
    $this->setExpectedException(“Exception”);
    $foo = new Foo();
    $foo->functionWithException();
    }
    }

    View Slide

  32. TechAdemy.nl
    Mocking & Stubbing

    View Slide

  33. TechAdemy.nl
    untestable code!

    View Slide

  34. TechAdemy.nl
    class MyMailer {
    protected $_from;
    protected $_body;
    protected $_subject;
    function setFrom($from) {
    $this->_from = $from;
    }
    .......
    function mail(array $to) {
    $count = 0;
    foreach ($to as $recipient) {
    if (mail($recipient, $this->_subject, $this->_body)) $count++;
    }
    return $count;
    }
    }

    View Slide

  35. TechAdemy.nl
    class MyMailer {
    protected $_from;
    protected $_body;
    protected $_subject;
    function setFrom($from) {
    $this->_from = $from;
    }
    .......
    function mail(array $to) {
    $count = 0;
    foreach ($to as $recipient) {
    if ($this->_mail($recipient)) $count++;
    }
    return $count;
    }
    protected function _mail($to) {
    return mail($to, $this->_subject, $this->_body);
    }
    }

    View Slide

  36. TechAdemy.nl
    include_once "mail.php";
    class mailTest extends PHPUnit_Framework_TestCase
    {
    ...
    public function testMail() {
    $mailer = new MyMailer();
    $mailer->setSubject("blaat");
    $mailer->setFrom("[email protected]");
    $mailer->setBody("meeh");
    $to = array("[email protected]", "[email protected]", "[email protected]");
    $this->assertEquals($mailer->mail($to), 3);
    }
    }

    View Slide

  37. TechAdemy.nl
    include_once "mail.php";
    class Mock_MyMailer extends MyMailer {
    protected function _mail($to) {
    return true;
    }
    }
    class mailTest extends PHPUnit_Framework_TestCase
    {
    ...
    public function testMail() {
    $mailer = new Mock_MyMailer();
    $mailer->setSubject("blaat");
    $mailer->setFrom("[email protected]");
    $mailer->setBody("meeh");
    $to = array("[email protected]", "[email protected]", "[email protected]");
    $this->assertEquals($mailer->mail($to), 3);
    }
    }

    View Slide

  38. TechAdemy.nl
    class mailTest extends PHPUnit_Framework_TestCase
    {
    public function testMail() {
    $stub = $this->getMockBuilder('MyMailer', array('_mail'))->getMock();
    $stub->expects($this->any())
    ->method('_mail')
    ->will($this->returnValue(true));
    $stub->setSubject("blaat");
    $stub->setFrom("[email protected]");
    $stub->setBody("meeh");
    $to = array("[email protected]", "[email protected]", "[email protected]");
    $this->assertEquals($stub->mail($to), 3);
    }
    }

    View Slide

  39. TechAdemy.nl
    If you find that you cannot test your code
    through PHPUnit, you are doing it wrong!

    View Slide

  40. TechAdemy.nl
    public function pay(Article $article) {
    $psp = new PaymentProvider();
    $psp->setAmount($article->getAmount());
    return $psp->pay();
    }

    View Slide

  41. TechAdemy.nl
    public function setPaymentProvider(PaymentProvider $psp) {
    $this->_psp = $psp;
    }
    public function getPaymentProvider() {
    return $this->_psp;
    }
    public function pay(Article $article) {
    $psp = $this->getPaymentProvider();
    $psp->setAmount($article->getAmount());
    return $psp->pay();
    }

    View Slide

  42. TechAdemy.nl
    public function testPayAccepted() {
    $stub = $this->getMockBuilder(‘paymentprovider’, array(‘pay’))->getMock();
    $stub->expects($this->any())
    ->method(‘pay’)
    ->will($this->returnValue(true));
    $article = new Article();
    $article->setAmount(15);
    $foo = new Foo();
    $foo->setPaymentProvider($stub);
    $this->assertTrue($foo->pay($article));
    $this->assertEquals($user->getAmount(), 85);
    }

    View Slide

  43. TechAdemy.nl
    public function testPayFailed() {
    $stub = $this->getMockBuilder(‘paymentprovider’, array(‘pay’))->getMock();
    $stub->expects($this->any())
    ->method(‘pay’)
    ->will($this->returnValue(false));
    $article = new Article();
    $article->setAmount(15);
    $foo = new Foo();
    $foo->setPaymentProvider($stub);
    $this->assertFalse($foo->pay($article));
    $this->assertEquals($user->getAmount(), 100);
    }

    View Slide