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
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Alexandre Salomé
November 24, 2011
Programming
500
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
290
Symfony Form - Practical use cases
alexandresalome
2
200
Tests in a Symfony Application
alexandresalome
0
490
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
770
Ma stratégie de tests
alexandresalome
0
340
Migrate from Symfony to Silex
alexandresalome
1
1.4k
Other Decks in Programming
See All in Programming
Generative UI & AI-Assistants for Your Angular Solutions
manfredsteyer
PRO
1
230
Embedded SREと共に達成した会員管理システムのAWS移行 - SRE NEXT 2026 ランチスポンサーセッション
niftycorp
PRO
1
3.1k
<title><a id="</title>君はこのHTMLをパースできるか"></a></title> #雑LT_study
pizzacat83
0
110
そこに3びきプロダクトがいるじゃろう——生成AI時代における“価値が届かない理由”の構造
kosuket
0
200
FDEが実現するAI駆動経営の現在地
gonta
2
230
AWS CDK を「作」ってみた 〜フルスクラッチで見えた CDK の裏側〜 / aws-cdk-from-scratch
gotok365
3
2.6k
人間の目はかわらない、だからJPEGは30年もつ
yuzneri
12
16k
任せる範囲はこう広がった / How the Scope of AI Delegation Has Expanded
nrslib
1
280
Google Apps Script で Ruby を動かす
kawahara
0
110
使いながら育てる Claude Code — 開発フローの1コマンド化 × 繰り返し指摘の自動仕組み化
shiki_kakaku
0
550
AWS DevOps AgentのAzure接続機能を検証して見えた活用法/Use Cases Verified for the AWS DevOps Agent's Azure Connectivity Feature
masakiokuda
0
120
「正の参照」と 「負の導出」で組む ハーネスエンジニアリング
cottpan
1
150
Featured
See All Featured
Reality Check: Gamification 10 Years Later
codingconduct
0
2.2k
Gemini Prompt Engineering: Practical Techniques for Tangible AI Outcomes
mfonobong
2
470
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
500
Are puppies a ranking factor?
jonoalderson
1
3.7k
We Have a Design System, Now What?
morganepeng
55
8.2k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.4k
Side Projects
sachag
455
43k
Designing Experiences People Love
moore
143
24k
First, design no harm
axbom
PRO
2
1.2k
30 Presentation Tips
portentint
PRO
1
350
Visualization
eitanlees
152
17k
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9.1k
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