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

Unit Tests in Symfony2

Unit Tests in Symfony2

A talk I made on SymfonyPot Paris May 2013. Symfony2 Test Culture, how to write unit tests etc. Thanks to @benjaM1 for the nice Theodo design.

Marek Kalnik

May 14, 2013
Tweet

More Decks by Marek Kalnik

Other Decks in Programming

Transcript

  1. 2 Symfony is one of the few Symfony is one

    of the few PHP projects (...) promoting PHP projects (...) promoting radical changes to the way radical changes to the way developers work developers work Fabien Potencier Fabien Potencier
  2. 3 <?php include 'includes/opendb.php'; include 'includes/header.inc'; ?> <h1>Orders</h1> <table> <?php

    $sql = “SELECT * FROM orders WHERE client_id = $GET['client_id']“; $result = mysql_query($sql); if ($result) { while ($row = mysql_fetch_row($result)) { echo “<tr><td>$row['label']</td><td>$row['value']</td><tr>”; } } ?> </table> <?php include 'includes/closedb.php'; include 'includes/footer.inc'; ?> <?php include 'includes/opendb.php'; include 'includes/header.inc'; ?> <h1>Orders</h1> <table> <?php $sql = “SELECT * FROM orders WHERE client_id = $GET['client_id']“; $result = mysql_query($sql); if ($result) { while ($row = mysql_fetch_row($result)) { echo “<tr><td>$row['label']</td><td>$row['value']</td><tr>”; } } ?> </table> <?php include 'includes/closedb.php'; include 'includes/footer.inc'; ?> PHP began with code like that (me too) PHP began with code like that (me too)
  3. 4 <?php include 'includes/opendb.php'; include 'includes/header.inc'; ?> <h1>Orders</h1> <table> <?php

    $sql = “SELECT * FROM orders WHERE client_id = $GET['client_id']“; $result = mysql_query($sql); if ($result) { while ($row = mysql_fetch_row($result)) { echo “<tr><td>$row['label']</td><td>$row['value']</td><tr>”; } } ?> </table> <?php include 'includes/closedb.php'; include 'includes/footer.inc'; ?> <?php include 'includes/opendb.php'; include 'includes/header.inc'; ?> <h1>Orders</h1> <table> <?php $sql = “SELECT * FROM orders WHERE client_id = $GET['client_id']“; $result = mysql_query($sql); if ($result) { while ($row = mysql_fetch_row($result)) { echo “<tr><td>$row['label']</td><td>$row['value']</td><tr>”; } } ?> </table> <?php include 'includes/closedb.php'; include 'includes/footer.inc'; ?> We want to improve our work We want to improve our work DIFFICULT TO REUSE SECURITY RISK NO SEPARATION OF CONCERNS NOT TESTED!
  4. 5 We have to participate in the We have to

    participate in the changes introduced by Symfony changes introduced by Symfony
  5. 6 We should unit test our We should unit test

    our applications applications
  6. 8 Impact on development Impact on development According to university

    study by David S. Janzen[1]: According to university study by David S. Janzen[1]: • reduces the number of lines of code reduces the number of lines of code • improves productivity improves productivity • less effort per line-of-code less effort per line-of-code • improves code structure improves code structure • makes developer more confident about their work makes developer more confident about their work [1] http://src.acm.org/subpages/gf_entries_06/DavidJanzen_src_gf06.pdf
  7. 9 TDD – even better TDD – even better Further

    improves the code stability and quality: Further improves the code stability and quality: • http://research.microsoft.com/en-us/groups/ese/nagappan_tdd.pdf http://research.microsoft.com/en-us/groups/ese/nagappan_tdd.pdf • http://research.microsoft.com/en-us/groups/ese/fp17288-bhat.pdf http://research.microsoft.com/en-us/groups/ese/fp17288-bhat.pdf • and others... and others... Most successful Theodo Most successful Theodo projects were written using projects were written using the TDD technique. the TDD technique.
  8. 11 Symfony2 tests Symfony2 tests • early versions ~5100 tests

    early versions ~5100 tests • today ~9000 tests today ~9000 tests • Documentation! Documentation! • http://symfony.com/doc/current/book/testing.html http://symfony.com/doc/current/book/testing.html • http://symfony.com/doc/current/cookbook/testing/index.html http://symfony.com/doc/current/cookbook/testing/index.html • http://symfony.com/doc/current/cookbook/form/unit_testing.html http://symfony.com/doc/current/cookbook/form/unit_testing.html
  9. 12 Interesting TestCases Interesting TestCases • FormComponent::FormIntegrationTestCase FormComponent::FormIntegrationTestCase • FormComponent::TypeTestCase

    FormComponent::TypeTestCase • *PerformanceTestCase *PerformanceTestCase • LocaleComponent::TestCase LocaleComponent::TestCase • FosUserBundle::FosUserExtensionTest FosUserBundle::FosUserExtensionTest • getFullConfig, getEmptyConfig getFullConfig, getEmptyConfig   • TheodoRogerCmsBundle ;-) TheodoRogerCmsBundle ;-)
  10. 15 Tools Tools PHPUnit running and writing the tests because

    it's the industry standard Phake (https://github.com/mlively/Phake) mocking because PHPUnit mocks are not flexible enough
  11. 16 Install Install // composer.json require-dev: { “phpunit/phpunit”: “*”, “phake/phake”:

    “*” } // composer.json require-dev: { “phpunit/phpunit”: “*”, “phake/phake”: “*” }
  12. 17 tests.bootstrap.php tests.bootstrap.php <?php require_once __DIR__ . '/bootstrap.php.cache'; Phake::setClient(Phake::CLIENT_PHPUNIT); <?php

    require_once __DIR__ . '/bootstrap.php.cache'; Phake::setClient(Phake::CLIENT_PHPUNIT); add it in phpunit.xml add it in phpunit.xml
  13. 18 the setUp the setUp <?php namespace Theodo\CmsBundle\Tests\Twig; use Theodo\CmsBundle\Twig\CmsEnablerExtension;

    use Phake; class CmsEnablerExtensionTest extends \PHPUnit_Framework_TestCase { public function setUp() { $this->securityContext = Phake::mock('Symfony\Component\Security\Core\SecurityContextInterface'); $this->enabler = new CmsEnablerExtension($this->securityContext); } } <?php namespace Theodo\CmsBundle\Tests\Twig; use Theodo\CmsBundle\Twig\CmsEnablerExtension; use Phake; class CmsEnablerExtensionTest extends \PHPUnit_Framework_TestCase { public function setUp() { $this->securityContext = Phake::mock('Symfony\Component\Security\Core\SecurityContextInterface'); $this->enabler = new CmsEnablerExtension($this->securityContext); } }
  14. 19 the mock the mock <?php namespace Theodo\CmsBundle\Tests\Twig; use Theodo\CmsBundle\Twig\CmsEnablerExtension;

    use Phake; class CmsEnablerExtensionTest extends \PHPUnit_Framework_TestCase { public function setUp() { $this->securityContext = Phake::mock('Symfony\Component\Security\Core\SecurityContextInterface'); $this->enabler = new CmsEnablerExtension($this->securityContext); } public function testChecksIfCmsShouldBeEnabled() { Phake::when($this->securityContext)->isGranted('ROLE_ADMIN', null) ->thenReturn(true); } } <?php namespace Theodo\CmsBundle\Tests\Twig; use Theodo\CmsBundle\Twig\CmsEnablerExtension; use Phake; class CmsEnablerExtensionTest extends \PHPUnit_Framework_TestCase { public function setUp() { $this->securityContext = Phake::mock('Symfony\Component\Security\Core\SecurityContextInterface'); $this->enabler = new CmsEnablerExtension($this->securityContext); } public function testChecksIfCmsShouldBeEnabled() { Phake::when($this->securityContext)->isGranted('ROLE_ADMIN', null) ->thenReturn(true); } }
  15. 20 the test the test <?php namespace Theodo\CmsBundle\Tests\Twig; use Theodo\CmsBundle\Twig\CmsEnablerExtension;

    use Phake; class CmsEnablerExtensionTest extends \PHPUnit_Framework_TestCase { public function setUp() { $this->securityContext = Phake::mock('Symfony\Component\Security\Core\SecurityContextInterface'); $this->enabler = new CmsEnablerExtension($this->securityContext); } public function testChecksIfCmsShouldBeEnabled() { Phake::when($this->securityContext)->isGranted('ROLE_ADMIN', null) ->thenReturn(true); $this->assertTrue($this->enabler->isEnabled()); Phake::verify($this->securityContext, Phake::times(1))->isGranted('ROLE_ADMIN', null); } } <?php namespace Theodo\CmsBundle\Tests\Twig; use Theodo\CmsBundle\Twig\CmsEnablerExtension; use Phake; class CmsEnablerExtensionTest extends \PHPUnit_Framework_TestCase { public function setUp() { $this->securityContext = Phake::mock('Symfony\Component\Security\Core\SecurityContextInterface'); $this->enabler = new CmsEnablerExtension($this->securityContext); } public function testChecksIfCmsShouldBeEnabled() { Phake::when($this->securityContext)->isGranted('ROLE_ADMIN', null) ->thenReturn(true); $this->assertTrue($this->enabler->isEnabled()); Phake::verify($this->securityContext, Phake::times(1))->isGranted('ROLE_ADMIN', null); } }
  16. 21 and more and more <?php namespace Theodo\CmsBundle\Tests\Twig; use Theodo\CmsBundle\Twig\CmsEnablerExtension;

    use Phake; class CmsEnablerExtensionTest extends \PHPUnit_Framework_TestCase { public function setUp() { $this->securityContext = Phake::mock('Symfony\Component\Security\Core\SecurityContextInterface'); $this->enabler = new CmsEnablerExtension($this->securityContext); } public function testChecksIfCmsShouldBeEnabled() { Phake::when($this->securityContext)->isGranted('ROLE_ADMIN', null) ->thenReturn(true); $this->enabler->setEnv('cms'); $this->assertTrue($this->enabler->isEnabled()); $this->enabler->setEnv('prod'); $this->assertFalse($this->enabler->isEnabled()); Phake::verify($this->securityContext, Phake::times(1))->isGranted('ROLE_ADMIN', null); } } <?php namespace Theodo\CmsBundle\Tests\Twig; use Theodo\CmsBundle\Twig\CmsEnablerExtension; use Phake; class CmsEnablerExtensionTest extends \PHPUnit_Framework_TestCase { public function setUp() { $this->securityContext = Phake::mock('Symfony\Component\Security\Core\SecurityContextInterface'); $this->enabler = new CmsEnablerExtension($this->securityContext); } public function testChecksIfCmsShouldBeEnabled() { Phake::when($this->securityContext)->isGranted('ROLE_ADMIN', null) ->thenReturn(true); $this->enabler->setEnv('cms'); $this->assertTrue($this->enabler->isEnabled()); $this->enabler->setEnv('prod'); $this->assertFalse($this->enabler->isEnabled()); Phake::verify($this->securityContext, Phake::times(1))->isGranted('ROLE_ADMIN', null); } }
  17. 22 group group <?php namespace Theodo\CmsBundle\Tests\Twig; use Theodo\CmsBundle\Twig\CmsEnablerExtension; use Phake;

    /** * @group unit */ class CmsEnablerExtensionTest extends \PHPUnit_Framework_TestCase { public function setUp() { $this->securityContext = Phake::mock('Symfony\Component\Security\Core\SecurityContextInterface'); $this->enabler = new CmsEnablerExtension($this->securityContext); } <?php namespace Theodo\CmsBundle\Tests\Twig; use Theodo\CmsBundle\Twig\CmsEnablerExtension; use Phake; /** * @group unit */ class CmsEnablerExtensionTest extends \PHPUnit_Framework_TestCase { public function setUp() { $this->securityContext = Phake::mock('Symfony\Component\Security\Core\SecurityContextInterface'); $this->enabler = new CmsEnablerExtension($this->securityContext); } $ bin/phpunit -c app/ --group unit $ bin/phpunit -c app/ --group unit
  18. 23 other stuff other stuff refactor your tests – it's

    a code to maintain too! use fixtures (Alice, Phaker) ! be close to production