• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Mocking Dependencies in PHPUnit

Mocking Dependencies in PHPUnit



Presentation on mocking dependencies in PHPUnit

Presentation on mocking dependencies in PHPUnit



Total Views
Views on SlideShare
Embed Views



1 Embed 9

http://librosweb.es 9



Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
Post Comment
Edit your comment

    Mocking Dependencies in PHPUnit Mocking Dependencies in PHPUnit Presentation Transcript

    • 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 dependencies, but much smaller scale
    • 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
    • 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!
    • 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
    • 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 unit tests!
    • Mocking
    • 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
    • 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
    • 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
    • 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()) ->method('setUserId') ->with(1); $post = new Post($user); $post->retrieve(10); $post->getUserInfo(); }
    • 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) 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 :)
    • Test Stub ✤ Ensures a method is a called correctly ✤ Generates a “fake response” ✤ Response allows for different cases to be tested
    • Response
    • 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)); ...
    • 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
    • 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 validateComment() { //doesn't rely on User at all } }
    • 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
    • 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) ✤ We can easily cover a variety of outcomes
    • Constructor <?phpclass PDOTestHelper extends PDO{ public function __construct(){}} Overridden constructor allows us to mock!
    • Setup/TearDown public function setUp() { $this->pdo = $this->getMock('PDOTestHelper'); $this->statement = $this->getMock('PDOStatement'); } public function tearDown() { unset($pdo); unset($statement); }
    • 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.
    • 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!
    • Stubbing Fetch! $simData = array( ‘id‘ => 1, ‘firstName‘ => ‘Lloyd’, ‘lastName‘ => ‘Christmas’, ‘occupation‘ => ‘Dog Groomer’ ); $this->statement->expects($this->once()) ->method('fetch') ->will($this->returnValue($simData));
    • 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 anything else ✤ Spies! ✤ Don’t talk to the API
    • 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
    • Practical API Testing ✤ Generally, mocks suffice! ✤ If the method is transforming data, stub it! ✤ Spies are good to track multiple calls in same method
    • 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(); }
    • 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(); }
    • 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)
    • Summary ✤ Injected Dependencies = Increased Testability ✤ Mock/Stub/Dummy ✤ Don’t do more than you need to! ✤ Practice makes perfect
    • Victory! Mocking effectively leads to better tests and better tests lead to better applications!
    • Thank you! ✤ Freenode: mfrost503 ✤ Joind.in: http://joind.in/8693