Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PHPUnit Workshop CCXX13

Avatar for Joshua Thijssen Joshua Thijssen
November 07, 2013
190

PHPUnit Workshop CCXX13

Avatar for Joshua Thijssen

Joshua Thijssen

November 07, 2013
Tweet

Transcript

  1. 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: jthijssen@noxlogic.nl Twitter: @jaytaph
  2. 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..
  3. TechAdemy.nl • Unit testing • Integration testing • Stress testing

    • Regression testing • Acceptance testing • A/B testing • Security testing • Usability testing Much more....
  4. TechAdemy.nl FooTest.php: Foo.php <?php class foo { public function baz()

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

    { return 1; } public function isOdd($number) { if (($number & 1) == 1) { return true; } else { return false; } } } <?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)); } }
  6. TechAdemy.nl FooTest.php: <?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)); } }
  7. 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)
  8. 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.
  9. 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!
  10. TechAdemy.nl • writing tests increases coding time. • writing tests

    decreases debug time. • overall decreases development time.
  11. 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 ?
  12. TechAdemy.nl <?php class fooTest extends PHPUnit_Framework_TestCase { public function testBlahBlah()

    { $foo = new Bar(); .... } public function testBlah() { $foo = new Bar(); .... } }
  13. TechAdemy.nl <?php class fooTest extends PHPUnit_Framework_TestCase { public setUp() {

    $this->_foo = new Bar(); } public tearDown() { unset($this->_foo); } public function testBlahBlah() { .... } public function testBlah() { .... } }
  14. TechAdemy.nl <?php class fooTest extends PHPUnit_Framework_TestCase { public function testFoo()

    { .... } /** * @depends testFoo */ public function testBar() { .... } }
  15. TechAdemy.nl <?php 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); ... } }
  16. TechAdemy.nl <?php 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) ); } }
  17. TechAdemy.nl <?php 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) { } } }
  18. TechAdemy.nl <?php class fooTest extends PHPUnit_Framework_TestCase { /** * @expectedException

    Exception */ public function testCount() { $foo = new Foo(); $foo->functionWithException(); } }
  19. TechAdemy.nl <?php class fooTest extends PHPUnit_Framework_TestCase { public function testCount()

    { $this->setExpectedException(“Exception”); $foo = new Foo(); $foo->functionWithException(); } }
  20. TechAdemy.nl <?php 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; } }
  21. TechAdemy.nl <?php 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); } }
  22. TechAdemy.nl <?php include_once "mail.php"; class mailTest extends PHPUnit_Framework_TestCase { ...

    public function testMail() { $mailer = new MyMailer(); $mailer->setSubject("blaat"); $mailer->setFrom("jthijssen@example.com"); $mailer->setBody("meeh"); $to = array("aap@example.com", "blaat@example.com", "all@example.com"); $this->assertEquals($mailer->mail($to), 3); } }
  23. TechAdemy.nl <?php 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("jthijssen@example.com"); $mailer->setBody("meeh"); $to = array("aap@example.com", "blaat@example.com", "all@example.com"); $this->assertEquals($mailer->mail($to), 3); } }
  24. TechAdemy.nl <?php 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("jthijssen@example.com"); $stub->setBody("meeh"); $to = array("aap@example.com", "blaat@example.com", "all@example.com"); $this->assertEquals($stub->mail($to), 3); } }
  25. TechAdemy.nl If you find that you cannot test your code

    through PHPUnit, you are doing it wrong!
  26. TechAdemy.nl public function pay(Article $article) { $psp = new PaymentProvider();

    $psp->setAmount($article->getAmount()); return $psp->pay(); }
  27. 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(); }
  28. 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); }
  29. 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); }