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

Mocks, Stubs, Tests

Mocks, Stubs, Tests

Alexandre Salomé

November 24, 2011
Tweet

More Decks by Alexandre Salomé

Other Decks in Programming

Transcript

  1. View Slide

  2. View Slide

  3. View Slide

  4. L’instant quizz

    View Slide

  5. Qui a déjà écrit
    des tests ?

    View Slide

  6. Qui a déjà utilisé
    PHPUnit ?

    View Slide

  7. Qui a déjà mocké
    une classe ?

    View Slide

  8. Séance de gym terminée.
    Merci

    View Slide

  9. View Slide









  10. View Slide


  11. View Slide



  12. View Slide



  13. View Slide









  14. Le format des tests dépend du sujet

    View Slide

  15. Quand je casserais quelque chose
    Elle ne me ralentira pas dans mon travail
    Le code coverage sera de 100%

    View Slide

  16. Quand je casserais quelque chose
    Elle ne me ralentira pas dans mon travail
    Le code coverage sera de 100%

    View Slide

  17. View Slide

  18. 22,4% 97%
    42%
    Pas bien Bien

    View Slide

  19. 22,4% 97%
    42%
    Pas bien Bien

    View Slide


  20. View Slide




  21. View Slide





  22. View Slide






  23. View Slide

  24. class PHPTour
    {
    public $totalCost;
    public $attendees;
    public function getPlacePrice()
    {
    return $this->totalCost / $this->attendees;
    }
    }

    View Slide

  25. class PHPTourTest extends PHPUnit_Framework_TestCase
    {
    public function testForCoverage()
    {
    $tour = new PHPTour();
    $tour->totalCost = 40000;
    $tour->attendees = 100;
    $this->assertEquals(400, $tour->getPlacePrice());
    }
    }

    View Slide

  26. class PHPTourTest extends PHPUnit_Framework_TestCase
    {
    public function testForCoverage()
    {
    $tour = new PHPTour();
    $tour->totalCost = 40000;
    $tour->attendees = 100;
    $this->assertEquals(400, $tour->getPlacePrice());
    }
    }

    View Slide

  27. $tour->attendees = 0;

    View Slide

  28. $tour->attendees = 0;
    Division par zéro

    View Slide

  29. View Slide




  30. View Slide

  31. class CodeCoverage
    {
    private $field1;
    // …
    private $fieldN;
    // …
    private $field30;
    // Powerpoint coding standards
    public function setFieldN($n) { $this->fieldn = $n; }
    public function getFieldN() { return $this->fieldN; }
    }

    View Slide

  32. class CodeCoverage
    {
    // …
    public function compute()
    {
    $troll = $field1 * $field2 / (($field3 * $field4) * $field5) *
    $field6 / $field7 * $field8;
    $troll2 = $field9 * $field10 / cos($field11);
    $troll3 = $field12 * tan($field13);
    return $troll * log($troll2) / sin($troll3) * $field14 /*
    (;;)(^_^)(;;) */;
    }
    }

    View Slide

  33. class CodeCoverageTest extends PHPUnit_Framework_TestCase
    {
    public function testSetField1AndGetField1ReturnsCorrectValue()
    {
    $cc = new CodeCoverage();
    $cc->setField1(’fuu');
    $this->assertEquals(’fuu', $cc->getField1());
    }
    // repeat for each fields
    }

    View Slide

  34. View Slide







  35. View Slide


  36. View Slide





  37. View Slide






  38. View Slide

  39. View Slide

  40. // Insert your code here

    View Slide

  41. class Car
    {
    public function __construct()
    {
    $this->engine = new Engine();
    }
    }

    View Slide

  42. class Car
    {
    public function __construct()
    {
    $this->engine = new Engine();
    }
    }

    View Slide

  43. class Car
    {
    public function __construct(EngineInterface $engine)
    {
    $this->engine = $engine;
    }
    }

    View Slide

  44. class Car
    {
    public function __construct(EngineInterface $engine)
    {
    $this->engine = $engine;
    }
    }

    View Slide

  45. class SausageShop
    {
    public function serve()
    {
    $sausage =
    SausageFactory::getNewSausage();
    $bread =
    BreadFactory::getNewBread();
    return
    $bread->upgradeWith($sausage);
    }
    }

    View Slide

  46. class SausageShop
    {
    public function serve()
    {
    $sausage =
    SausageFactory::getNewSausage();
    $bread =
    BreadFactory::getNewBread();
    return
    $bread->upgradeWith($sausage);
    }
    }

    View Slide

  47. class SausageShop
    {
    public function __construct(
    SausageFactory $sausageFactory,
    BreadFactory $breadFactory )
    {
    $this->sausageFactory = $sausageFactory;
    $this->breadFactory = $breadFactory;
    }
    public function serve()
    {
    $sausage =
    $this->sausageFactory->getNewSausage();
    $bread =
    $this->breadFactory->getNewBread();
    return $bread->upgradeWith($sausage);
    }
    }

    View Slide

  48. class SausageShop
    {
    public function __construct(
    SausageFactory $sausageFactory,
    BreadFactory $breadFactory )
    {
    $this->sausageFactory = $sausageFactory;
    $this->breadFactory = $breadFactory;
    }
    public function serve()
    {
    $sausage =
    $this->sausageFactory->getNewSausage();
    $bread =
    $this->breadFactory->getNewBread();
    return $bread->upgradeWith($sausage);
    }
    }

    View Slide

  49. class Customer
    {
    public function orderBeer()
    {
    $url = 'http://waiter/bring-me-a-
    beer/erdinger';
    return file_get_contents($url);
    }
    }

    View Slide

  50. class Customer
    {
    public function orderBeer()
    {
    $url = 'http://waiter/bring-me-a-
    beer/erdinger';
    return file_get_contents($url);
    }
    }

    View Slide

  51. class Customer
    {
    public function orderBeer(
    WaiterApi $api)
    {
    return $api->bring(‘erdinger’);
    }
    }

    View Slide

  52. class Customer
    {
    public function orderBeer(
    WaiterApi $api)
    {
    return $api->bring(‘erdinger’);
    }
    }

    View Slide

  53. Design by contract

    View Slide

  54. SINGLETONS

    View Slide

  55. View Slide

  56. View Slide

  57. View Slide

  58. View Slide

  59. abstract class BaseMedia
    {
    const TYPE_IMAGE;
    abstract public function getFile();
    public function getType() {
    switch (get_extension($this->getFile()))
    {
    case 'png‘:
    return self::TYPE_IMAGE;
    }
    }

    View Slide

  60. abstract class BaseMedia
    {
    const TYPE_IMAGE;
    abstract public function getFile();
    public function getType() {
    switch (get_extension($this->getFile()))
    {
    case 'png‘:
    return self::TYPE_IMAGE;
    }
    }

    View Slide

  61. Interface MediaInterface
    {
    const TYPE_IMAGE;
    public function getType();
    }

    View Slide

  62. View Slide



  63. View Slide





  64. View Slide



  65. Les mocks/stubs à notre secours !

    View Slide

  66. View Slide





  67. View Slide






  68. View Slide










  69. View Slide

  70. JIHANE MOSSALIM

    View Slide


  71. View Slide

  72. class MyClassTest extends PHPUnit_Framework_TestCase
    {
    public function testFoo()
    {
    $engine = $this->getMock('Engine');
    $car = new Car($engine);
    }
    }
    Tous les appels à Engine
    renverront « null »
    En fait…
    c‘est un stub

    View Slide






  73. View Slide

  74. // ...
    $engine = $this->getMock('Engine');
    $engine
    ->expects($this->once())
    ->method(‘start‘)
    ->will($this->returnValue(true))
    ;
    Un contrat est établi
    C’est un mock,
    un vrai

    View Slide

  75. • $mock
    • ->expects(…)
    • ->method('name')
    • ->with(…)
    • ->will(…)

    View Slide

  76. expects(PHPUnit_…_Matcher_Invocation)
    $this->exactly($n)
    $this->never()
    $this->any()
    $this->atLeastOnce()

    View Slide

  77. with(PHPUnit_Framework_Constraint)
    $this->exactly($n)
    $this->arrayHasKey ('...')
    $this->any()

    View Slide

  78. will(PHPUnit_Framework_MockObject_Stub)
    $this->returnValue($value)
    $this->returnArgument($n)
    $this->returnCallback($c)
    $this->throwException($e)
    $this->onConsecutiveCalls(1, 2, 3)

    View Slide

  79. View Slide

  80. namespace Sensio\Bundle\PlatformBundle\OAuth;
    use Symfony\Component\HttpFoundation\Session;
    class OAuthClient
    {
    // … properties declaration …
    public function __construct($serviceName, \OAuth $oauth, $endPoint, $authorizeUri,
    $requestTokenUri, $accessTokenUri, Session $session = null)
    {
    $this->serviceName = $serviceName;
    $this->oauth = $oauth;
    $this->endPoint = $endPoint;
    $this->authorizeUri = $authorizeUri;
    $this->requestTokenUri = $requestTokenUri;
    $this->accessTokenUri = $accessTokenUri;
    $this->session = $session;
    $this->sessionOAuthTokenName = sprintf('oauth/_%s.oauth_token',
    $this->serviceName);
    $this->sessionOAuthTokenSecretName = sprintf('oauth/_%s.oauth_token_secret',
    $this->serviceName);
    }
    // … other methods …

    View Slide

  81. public function getRequestToken($redirectUri = null)
    {
    if ($this->session) {
    $this->session->remove($this->sessionOAuthTokenName);
    $this->session->remove($this->sessionOAuthTokenSecretName);
    }
    $requestToken = $this->oauth->getRequestToken(
    $this->requestTokenUri,
    $redirectUri);
    if ($requestToken === false) {
    throw new \OAuthException('Failed fetching request token,
    response was: ’
    .$this->oauth->getLastResponse());
    }
    if ($this->session) {
    $this->session->set($this->sessionOAuthTokenName,
    $requestToken['oauth_token']);
    $this->session->set($this->sessionOAuthTokenSecretName,
    $requestToken['oauth_token_secret']);
    }
    return $requestToken;
    }

    View Slide

  82. public function retrieveAccessToken($oauthSessionHandle = '', $verifierToken)
    {
    if ($this->session) {
    if (($token = $this->session->get($this->sessionOAuthTokenName))
    && ($tokenSecret = $this->session->get(
    $this->sessionOAuthTokenSecretName))
    ) {
    $this->oauth->setToken($token, $tokenSecret);
    }
    }
    $response = $this->oauth->getAccessToken($this->accessTokenUri,
    $oauthSessionHandle,
    $verifierToken);
    if (false === $response) {
    throw new \OAuthException('Failed fetching access token, response was: '.
    $this->oauth->getLastResponse());
    }
    return $response;
    }
    }

    View Slide

  83. public function setToken($token, $tokenSecret)
    {
    $this->oauth->setToken($token, $tokenSecret);
    }
    public function get($path)
    {
    $url = sprintf('%s/%s', $this->endPoint, ltrim($path, '/'));
    $state = $this->oauth->fetch($url);
    if (!$state) {
    throw new \RuntimeException(sprintf(Can\’t fetch resource %s',
    $url));
    }
    return $this->oauth->getLastResponse();
    }

    View Slide


  84. View Slide

  85. class myTest extends PHPUnit_Framework_TestCase {
    public function testGetRequestToken() {
    $oauth = $this->getMock('OAuth');
    $oauth
    ->expects($this->once())
    ->method('getRequestToken')
    ->will($this->returnValue('ok'))
    ;
    $client = new OAuthClient(
    'foo', $oauth,
    'bar', 'bar', 'bar', 'bar', 'bar');
    $this->assertEquals('ok', $client->getRequestToken());
    }
    }

    View Slide

  86. class myTest extends PHPUnit_Framework_TestCase {
    /** @expectedException LogicException */
    public function testGetRequestTokenWithError() {
    $oauth = $this->getMock('OAuth');
    $oauth
    ->expects($this->once())
    ->method('getRequestToken')
    ->will($this->returnValue(false));
    $client = new OAuthClient('foo',
    $oauth,
    'bar', 'bar', 'bar', 'bar', 'bar');
    $client->getRequestToken();
    }
    }

    View Slide









  87. View Slide

  88. Questions?

    View Slide

  89. View Slide