Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Mocks, Stubs, Tests
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Alexandre Salomé
November 24, 2011
Programming
490
5
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Mocks, Stubs, Tests
Alexandre Salomé
November 24, 2011
More Decks by Alexandre Salomé
See All by Alexandre Salomé
Integrating WordPress and Symfony
alexandresalome
0
270
Symfony Form - Practical use cases
alexandresalome
2
190
Tests in a Symfony Application
alexandresalome
0
480
Les tests dans une application Symfony
alexandresalome
5
2.4k
Symfony Forms - Advanced Use Cases
alexandresalome
2
1k
Migrer vers une architecture micro-services : points de contrôle pour une migration réussie
alexandresalome
2
1.3k
Concevoir des back-offices performants
alexandresalome
1
760
Ma stratégie de tests
alexandresalome
0
330
Migrate from Symfony to Silex
alexandresalome
1
1.4k
Other Decks in Programming
See All in Programming
Webフレームワークの ベンチマークについて
yusukebe
0
160
Vite+ Unified Toolchain for the Web
naokihaba
0
230
jQueryをバージョンアップする前に使いたいjQuery Migrate
matsuo_atsushi
0
200
作って学ぶ、 JSX (TSX) ランタイムの基本
syumai
7
1.6k
ADKを使って簡単にAIエージェントを作ってみよう
k1mu21
0
250
These Five Tricks Can Make Your Apps Greener, Cheaper, & Nicer
hollycummins
0
280
肥大化するレガシーコードに立ち向かうためのインターフェース分離と依存の逆転 / JJUG CCC 2026 Spring
hirokunimaeta
0
530
ECSアプリログをFireLensでコスト削減しようとしたけど諦めた話 in Fargate×Node.js
akihisaikeda
2
4k
Spec-Driven Development with AI-Agents: From High-Level Requirements to Working Software
antonarhipov
2
480
Oxcを導入して開発体験が向上した話
yug1224
4
300
Lessons from Spec-Driven Development
simas
PRO
0
150
AIとRubyの静的型付け
ukin0k0
0
560
Featured
See All Featured
Building AI with AI
inesmontani
PRO
1
1.1k
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
62
44k
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.3k
How Software Deployment tools have changed in the past 20 years
geshan
0
34k
Testing 201, or: Great Expectations
jmmastey
46
8.2k
Scaling GitHub
holman
464
140k
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
1
250
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
580
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
360
Odyssey Design
rkendrick25
PRO
2
690
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
The Invisible Side of Design
smashingmag
302
52k
Transcript
None
None
None
L’instant quizz
Qui a déjà écrit des tests ?
Qui a déjà utilisé PHPUnit ?
Qui a déjà mocké une classe ?
Séance de gym terminée. Merci
None
• – – – • – – •
•
• •
• •
• • – • – • – • Le format
des tests dépend du sujet
Quand je casserais quelque chose Elle ne me ralentira pas
dans mon travail Le code coverage sera de 100%
Quand je casserais quelque chose Elle ne me ralentira pas
dans mon travail Le code coverage sera de 100%
None
22,4% 97% 42% Pas bien Bien
22,4% 97% 42% Pas bien Bien
•
• • •
• • • –
• • • – –
class PHPTour { public $totalCost; public $attendees; public function getPlacePrice()
{ return $this->totalCost / $this->attendees; } }
class PHPTourTest extends PHPUnit_Framework_TestCase { public function testForCoverage() { $tour
= new PHPTour(); $tour->totalCost = 40000; $tour->attendees = 100; $this->assertEquals(400, $tour->getPlacePrice()); } }
class PHPTourTest extends PHPUnit_Framework_TestCase { public function testForCoverage() { $tour
= new PHPTour(); $tour->totalCost = 40000; $tour->attendees = 100; $this->assertEquals(400, $tour->getPlacePrice()); } }
$tour->attendees = 0;
$tour->attendees = 0; Division par zéro
None
• – •
<?php class CodeCoverage { private $field1; // … private $fieldN;
// … private $field30; // Powerpoint coding standards public function setFieldN($n) { $this->fieldn = $n; } public function getFieldN() { return $this->fieldN; } }
<?php 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 /* (;;)(^_^)(;;) */; } }
<?php class CodeCoverageTest extends PHPUnit_Framework_TestCase { public function testSetField1AndGetField1ReturnsCorrectValue() {
$cc = new CodeCoverage(); $cc->setField1(’fuu'); $this->assertEquals(’fuu', $cc->getField1()); } // repeat for each fields }
None
• • • • • •
•
• • – –
• • – – –
None
<?php // Insert your code here
<?php class Car { public function __construct() { $this->engine =
new Engine(); } }
<?php class Car { public function __construct() { $this->engine =
new Engine(); } }
<?php class Car { public function __construct(EngineInterface $engine) { $this->engine
= $engine; } }
<?php class Car { public function __construct(EngineInterface $engine) { $this->engine
= $engine; } }
<?php class SausageShop { public function serve() { $sausage =
SausageFactory::getNewSausage(); $bread = BreadFactory::getNewBread(); return $bread->upgradeWith($sausage); } }
<?php class SausageShop { public function serve() { $sausage =
SausageFactory::getNewSausage(); $bread = BreadFactory::getNewBread(); return $bread->upgradeWith($sausage); } }
<?php 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); } }
<?php 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); } }
<?php class Customer { public function orderBeer() { $url =
'http://waiter/bring-me-a- beer/erdinger'; return file_get_contents($url); } }
<?php class Customer { public function orderBeer() { $url =
'http://waiter/bring-me-a- beer/erdinger'; return file_get_contents($url); } }
<?php class Customer { public function orderBeer( WaiterApi $api) {
return $api->bring(‘erdinger’); } }
<?php class Customer { public function orderBeer( WaiterApi $api) {
return $api->bring(‘erdinger’); } }
Design by contract
SINGLETONS
None
None
None
None
<?php abstract class BaseMedia { const TYPE_IMAGE; abstract public function
getFile(); public function getType() { switch (get_extension($this->getFile())) { case 'png‘: return self::TYPE_IMAGE; } }
<?php abstract class BaseMedia { const TYPE_IMAGE; abstract public function
getFile(); public function getType() { switch (get_extension($this->getFile())) { case 'png‘: return self::TYPE_IMAGE; } }
<?php Interface MediaInterface { const TYPE_IMAGE; public function getType(); }
None
• •
• • – –
• • Les mocks/stubs à notre secours !
None
• • • •
• – – • •
• • • – – • • • •
JIHANE MOSSALIM
•
<?php 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
• • – – •
<?php // ... $engine = $this->getMock('Engine'); $engine ->expects($this->once()) ->method(‘start‘) ->will($this->returnValue(true))
; Un contrat est établi C’est un mock, un vrai
• $mock • ->expects(…) • ->method('name') • ->with(…) • ->will(…)
expects(PHPUnit_…_Matcher_Invocation) $this->exactly($n) $this->never() $this->any() $this->atLeastOnce()
with(PHPUnit_Framework_Constraint) $this->exactly($n) $this->arrayHasKey ('...') $this->any()
will(PHPUnit_Framework_MockObject_Stub) $this->returnValue($value) $this->returnArgument($n) $this->returnCallback($c) $this->throwException($e) $this->onConsecutiveCalls(1, 2, 3)
None
<?php 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 …
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; }
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; } }
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(); }
•
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()); } }
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(); } }
• – – • – – • –
Questions?
None