Mocking Dependencies in
PHPUnit
Matt Frost · IRC: mfrost503 · Feedback: http://joind.in/8693
We’ll be covering
✤ Defining dependencies
✤ Dependency Injection
✤ Test Doubles in Theory
✤ Test Doubles in Practice
What’s a dependency
✤ Unit Test Context
✤ A unit(s) of code that adds functionality to another unit of code
✤ Think system...
Why mock them?
✤ Unit tests should cover a single unit of code in isolation
✤ A bug in a dependency makes your test a gues...
Dependencies in the wild
class Auth
{
private $user;
public function __construct(User $user)
{
$this->user = $user;
}
publ...
Don’t do this!
class Auth{ public function authenticate($username, $pass){ $user = new User($username, $pass);$username = ...
Dependency Injection
✤ Helps make code testable
✤ Helps make code flexible
✤ Constructor/Accessor methods
MOAR Dependency Injection
✤ Dependencies become properties in the object in which they’re used
✤ Paramount for mocking in ...
Mocking
Defining Test Doubles
✤ Stand in for actual objects (think Stunt Doubles)
✤ Can simulate functionality from those objects
...
A few more points
✤ Can’t directly mock private or protected methods
✤ Only mock what you need to test
✤ In a pinch, Refle...
Theory
✤ Unit Test shouldn’t be dependent on external data source availability
✤ Unit Test vs. Integration Test
✤ “How do ...
Types of Test Doubles
✤ Mock
✤ Stub
✤ Dummy
✤ Spy
Mock
✤ Verifies that a method has been called correctly
✤ Doesn’t generate a response
Anatomy of a Mock
✤ Expectation
✤ Method
✤ Parameters (if applicable)
Mock Example
public function testSetUser()
{
$user = $this->getMock('User',array('setUserId'));
$user->expects($this->once...
Explanation
✤ Supposes $user->setUserId(1) will be called in the test
✤ Fails if $user->setUserId(1) is not called
Mock Implementation
public function getUserInfo()
{
// assume $this->data is populated from
// the $post->retrieve($id) me...
Test Stub
✤ Ensures a method is a called correctly
✤ Generates a “fake response”
✤ Response allows for different cases to ...
Response
Stub Example
public function testGetUserInfo()
{
$userInfo = array(
'first_name' => 'Joe',
'last_name' => 'Strummer',
'id'...
Stub Example Cont’d
...
$post = new Post($user);
$post->retrieve(10);
$information = $post->getUserInfo();
$this->assertEq...
Dummy
✤ It’s a place holder
✤ It has no expectations or behavior
✤ It satisfies a parameter list...
Dummy Example
<?php
class Comment
{
public function __construct($comment, User $user)
{
...
}
public function validateComm...
Dummy Example
public function testValidateComment()
{
$user = $this->getMock('User');
$commentText = "<script></script>";
...
Practical Examples!
✤ External Data Sources - don’t talk to em!
✤ APIs
✤ Database Responses
Stubbing PDO
✤ Constructor is not serializable, we must adapt!
✤ PDO::prepare - returns a PDO Statement (which we can stub...
Constructor
<?phpclass PDOTestHelper extends PDO{ public function __construct(){}}
Overridden constructor
allows us to moc...
Setup/TearDown
public function setUp()
{
$this->pdo = $this->getMock('PDOTestHelper');
$this->statement = $this->getMock('...
Stubbing a prepared statement
$this->pdo->expects($this->once())
->method('prepare')
->with($this->stringContains('SELECT ...
Stubbing the execute call
$this->statement->expects($this->once())
->method('execute')
->with($this->isType('array'))
->wi...
Stubbing Fetch!
$simData = array(
‘id‘ => 1,
‘firstName‘ => ‘Lloyd’,
‘lastName‘ => ‘Christmas’,
‘occupation‘ => ‘Dog Groom...
Returning Data
✤ Data Fixtures
✤ Data Providers
✤ Data should resemble what you expect to get back
Mocking API Calls
✤ Wrap it up, not just for testing for your own sanity!
✤ Once it’s wrapped it can be mocked like anythi...
Spies
✤ Helpful in making sure your method was called
✤ Or called a certain number of times
✤ Not commonly used, but I’ve ...
Practical API Testing
✤ Generally, mocks suffice!
✤ If the method is transforming data, stub it!
✤ Spies are good to track...
API Example
public function testGetTweets()
{
//mock example
$request = $this->getMock('Request',array('get'));
$request->...
Spy Example
public function testComplicatedMethod()
{
//spy example
$request = $this->getMock('Request',array('get'));
$re...
Helpful Tidbits - With()
✤ isType(String $type) - check by type
✤ stringContains($value) - string parameter
✤ contains($va...
Summary
✤ Injected Dependencies = Increased Testability
✤ Mock/Stub/Dummy
✤ Don’t do more than you need to!
✤ Practice mak...
Victory!
Mocking effectively leads to better tests and better tests lead to
better applications!
Thank you!
✤ Freenode: mfrost503
✤ Joind.in: http://joind.in/8693
Upcoming SlideShare
Loading in …5
×

Mocking Dependencies in PHPUnit

7,797 views

Published on

Presentation on mocking dependencies in PHPUnit

Published in: Technology
  • daamn, the monospace fonts are unreadable :(
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Mocking Dependencies in PHPUnit

  1. 1. Mocking Dependencies in PHPUnit Matt Frost · IRC: mfrost503 · Feedback: http://joind.in/8693
  2. 2. We’ll be covering ✤ Defining dependencies ✤ Dependency Injection ✤ Test Doubles in Theory ✤ Test Doubles in Practice
  3. 3. What’s a dependency ✤ Unit Test Context ✤ A unit(s) of code that adds functionality to another unit of code ✤ Think system dependencies, but much smaller scale
  4. 4. Why mock them? ✤ Unit tests should cover a single unit of code in isolation ✤ A bug in a dependency makes your test a guessing game ✤ We only want to know that the code we’re testing works
  5. 5. Dependencies in the wild class Auth { private $user; public function __construct(User $user) { $this->user = $user; } public function authenticate() { $username = $this->user->getUserName(); $password = $this->user->getHash(); $this->checkLogin($username,$password); } } Dependency Alert!
  6. 6. Don’t do this! class Auth{ public function authenticate($username, $pass){ $user = new User($username, $pass);$username = $user->getUserName();$password = $user->getHash();$this->checkLogin($username,$password);} User cannot be mocked
  7. 7. Dependency Injection ✤ Helps make code testable ✤ Helps make code flexible ✤ Constructor/Accessor methods
  8. 8. MOAR Dependency Injection ✤ Dependencies become properties in the object in which they’re used ✤ Paramount for mocking in unit tests!
  9. 9. Mocking
  10. 10. Defining Test Doubles ✤ Stand in for actual objects (think Stunt Doubles) ✤ Can simulate functionality from those objects ✤ Can fulfill the requirements of a type hinted method ✤ Can be used to make sure a method on the mock is called
  11. 11. A few more points ✤ Can’t directly mock private or protected methods ✤ Only mock what you need to test ✤ In a pinch, Reflection API can help test private/protected
  12. 12. Theory ✤ Unit Test shouldn’t be dependent on external data source availability ✤ Unit Test vs. Integration Test ✤ “How do I know if my query is right?” ✤ You’re testing code, not network availability
  13. 13. Types of Test Doubles ✤ Mock ✤ Stub ✤ Dummy ✤ Spy
  14. 14. Mock ✤ Verifies that a method has been called correctly ✤ Doesn’t generate a response
  15. 15. Anatomy of a Mock ✤ Expectation ✤ Method ✤ Parameters (if applicable)
  16. 16. Mock Example public function testSetUser() { $user = $this->getMock('User',array('setUserId')); $user->expects($this->once()) ->method('setUserId') ->with(1); $post = new Post($user); $post->retrieve(10); $post->getUserInfo(); }
  17. 17. Explanation ✤ Supposes $user->setUserId(1) will be called in the test ✤ Fails if $user->setUserId(1) is not called
  18. 18. Mock Implementation public function getUserInfo() { // assume $this->data is populated from // the $post->retrieve($id) method $userId = $this->data['user_id']; $this->user->setUserId($userId); return $this->user->retrieve(); } This is an example of code that would pass the previous test, it’s a fictional example...so I wouldn’t use the code :)
  19. 19. Test Stub ✤ Ensures a method is a called correctly ✤ Generates a “fake response” ✤ Response allows for different cases to be tested
  20. 20. Response
  21. 21. Stub Example public function testGetUserInfo() { $userInfo = array( 'first_name' => 'Joe', 'last_name' => 'Strummer', 'id' => 1, 'email' => 'joe.strummer@gmail.com' ); $user = $this->getMock('User', array('retrieve')); $user->expects($this->once()) ->method('retrieve') ->will($this->returnValue($userInfo)); ...
  22. 22. Stub Example Cont’d ... $post = new Post($user); $post->retrieve(10); $information = $post->getUserInfo(); $this->assertEquals('Joe',$information['first_name']); $this->assertEquals('Strummer',$information['last_name']); } Here we’re asserting that retrieve is called correctly by validating that we get back what we expect
  23. 23. Dummy ✤ It’s a place holder ✤ It has no expectations or behavior ✤ It satisfies a parameter list...
  24. 24. Dummy Example <?php class Comment { public function __construct($comment, User $user) { ... } public function validateComment() { //doesn't rely on User at all } }
  25. 25. Dummy Example public function testValidateComment() { $user = $this->getMock('User'); $commentText = "<script></script>"; $comment = new Comment($commentText,$user); $this->assertFalse($comment->validateComment()); } User fulfills the method signature, but doesn’t get used
  26. 26. Practical Examples! ✤ External Data Sources - don’t talk to em! ✤ APIs ✤ Database Responses
  27. 27. Stubbing PDO ✤ Constructor is not serializable, we must adapt! ✤ PDO::prepare - returns a PDO Statement (which we can stub) ✤ We can easily cover a variety of outcomes
  28. 28. Constructor <?phpclass PDOTestHelper extends PDO{ public function __construct(){}} Overridden constructor allows us to mock!
  29. 29. Setup/TearDown public function setUp() { $this->pdo = $this->getMock('PDOTestHelper'); $this->statement = $this->getMock('PDOStatement'); } public function tearDown() { unset($pdo); unset($statement); }
  30. 30. Stubbing a prepared statement $this->pdo->expects($this->once()) ->method('prepare') ->with($this->stringContains('SELECT * from table')) ->will($this->returnValue($this->statement)) Prepare will return a PDOStatement when executed successfully, so in order to stub the preparation and execution of the query, this is how we need to start.
  31. 31. Stubbing the execute call $this->statement->expects($this->once()) ->method('execute') ->with($this->isType('array')) ->will($this->returnValue($this->statement)); Since we’re expecting this call to succeed, we need to return the statement again. Once we get the statement back, we’ve successfully simulated the preparation and execution of a query!
  32. 32. Stubbing Fetch! $simData = array( ‘id‘ => 1, ‘firstName‘ => ‘Lloyd’, ‘lastName‘ => ‘Christmas’, ‘occupation‘ => ‘Dog Groomer’ ); $this->statement->expects($this->once()) ->method('fetch') ->will($this->returnValue($simData));
  33. 33. Returning Data ✤ Data Fixtures ✤ Data Providers ✤ Data should resemble what you expect to get back
  34. 34. Mocking API Calls ✤ Wrap it up, not just for testing for your own sanity! ✤ Once it’s wrapped it can be mocked like anything else ✤ Spies! ✤ Don’t talk to the API
  35. 35. Spies ✤ Helpful in making sure your method was called ✤ Or called a certain number of times ✤ Not commonly used, but I’ve found good use in testing APIs
  36. 36. Practical API Testing ✤ Generally, mocks suffice! ✤ If the method is transforming data, stub it! ✤ Spies are good to track multiple calls in same method
  37. 37. API Example public function testGetTweets() { //mock example $request = $this->getMock('Request',array('get')); $request->expects($this->once()) ->method('get') ->with('statuses'); $twitter = new Twitter($request); $twitter->getTweets(); }
  38. 38. Spy Example public function testComplicatedMethod() { //spy example $request = $this->getMock('Request',array('get')); $request->expects($this->exactly(3)) ->method('get'); $twitter = new Twitter($request); $twitter->complicatedMethod(); }
  39. 39. Helpful Tidbits - With() ✤ isType(String $type) - check by type ✤ stringContains($value) - string parameter ✤ contains($value) - array parameter ✤ hasArrayKey($key) ✤ greaterThan($value) ✤ isInstanceOf($className) ✤ matchesRegularExpression($pattern) ✤ equalTo($value)
  40. 40. Summary ✤ Injected Dependencies = Increased Testability ✤ Mock/Stub/Dummy ✤ Don’t do more than you need to! ✤ Practice makes perfect
  41. 41. Victory! Mocking effectively leads to better tests and better tests lead to better applications!
  42. 42. Thank you! ✤ Freenode: mfrost503 ✤ Joind.in: http://joind.in/8693

×