Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Mocks, Stubs, Tests
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Alexandre Salomé
November 24, 2011
Programming
520
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
310
Symfony Form - Practical use cases
alexandresalome
2
230
Tests in a Symfony Application
alexandresalome
0
500
Les tests dans une application Symfony
alexandresalome
5
2.5k
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
790
Ma stratégie de tests
alexandresalome
0
350
Migrate from Symfony to Silex
alexandresalome
1
1.4k
Other Decks in Programming
See All in Programming
Seven New Principles of Software Engineering
yegor256
0
460
クラウドゲーミングのパフォーマンス最適化に挑む / Cloud Gaming Performance Tuning
vivion
0
330
AI-Powered Domain-Driven Design
ziobrando
0
410
Web Framework Benchmark Battle 2026, Any%
a_matsuda
3
3.2k
そのデザイントークン、Flutterでも同じ見た目になりますか?
nakamizu
0
310
Coding with AI: How to trust the storyteller (AWS Community Day Adria, Ljubljana 2026)
slobodan
0
140
Vapor Mode でアクセシビリティは 壊れないか検証した話
fuqda
1
330
オーケストレーション記述言語 Katari
yukikurage
0
240
クラウドエージェントは、 何がそんなに便利なのか / what makes cloud agents so useful
rkaga
5
800
Performance Optimization With LLMs
xleitix
0
240
Herb in Rails 8.2: Your ERB views, now HTML-aware @ Kaigi on Rails 2026, Tokyo, Japan
marcoroth
2
420
ActionController meets Protocol Buffers
sorah
1
790
Featured
See All Featured
[RailsConf 2023] Rails as a piece of cake
palkan
59
7.1k
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
650
Building an army of robots
kneath
307
47k
Color Theory Basics | Prateek | Gurzu
gurzu
1
510
We Have a Design System, Now What?
morganepeng
55
8.4k
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.5k
First, design no harm
axbom
PRO
2
1.4k
For a Future-Friendly Web
brad_frost
184
11k
Pawsitive SEO: Lessons from My Dog (and Many Mistakes) on Thriving as a Consultant in the Age of AI
davidcarrasco
0
290
We Are The Robots
honzajavorek
0
440
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
1
660
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
62k
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