Test in Action – Week 3
      Stub / Mock
      Hubert Chan
Back to Basics
• Wikipedia said unit testing is
  – A software verification and validation method in
    which a programmer tests if individual units of
    source code are fit for use.
Dependency in the Test
• System Under Test (SUT) Dependency
  – SUT need another module to perform its task
     • Handler need a $dbmodel to perform query
     • $handler = new Handler($dbmodel);
Real Object is Hard to Test
• Real object
  – Supplies non-deterministic results
     • (e.g. the current temperature)
  – Difficult to create or reproduce (e.g. network fail)
  – Slow (e.g. database)
  – Does not yet exist or may change behavior
Substitute Dependency
• Using Fake
  – Fake is anything not real
• Fake techniques
  – Mock object
  – Stub object
  – Fake object
Stub Objects
• Stub Objects
  – Stubs provide canned answers to calls made
    during the test
  – Usually not responding at all to anything outside
    what's programmed in for the test
Fake Objects
• Fake Objects
  – Fake objects have working implementations
  – Usually take some shortcut, which makes them
    not suitable for production.
  – Example
     • An in-memory file system
     • An in-memory registry manager
Example: AlertSystem
Example: AlertSystem
• Component Overview
  – AlertSystem
     • Send notification to the targets, such as e-mail or SMS
       notifier.
  – NotifierInterface instance
     • Send actually notification to the target
  – NotifierTargetProviderInterface instance
     • Provide a target array to send notification
AlertSystem Test
• Dependency Analysis
  – Collaboration Classes
     • NotifierInterface
     • NotifierTargetProviderInterface

• Tests should
  – Only focus on AlertSystem
  – Fake the dependency
Make a Fake?
• FileNotifyTargetProvider
class FileNotifyTargetProvider
    implements NotifyTargetProviderInterface {

    function __construct($filename) {
        $this->_filename = $filename;
    }

    public function get_targets() {
        $targets = array();
        $handle = @fopen($this->_filename, "r");

        while (($target = fgets($handle)) !== FALSE) {
            $targets[] = $target;
        }
        return $targets;
    }
}
Make a Stub?
• StubNotifier
class StubNotifier implements NotifierInterface {
    public function notify($target, $content) {
    }
}
Example: Test Code
• Test Code
class AlertSystemTest extends PHPUnit_Framework_TestCase {
    public function test_sendNotify_FakeNStub_NoException() {
        $target_file = __DIR__ . '/data/targets.txt';

        $notifier = new StubNotifier();
        $provider = new FileNotifyTargetProvider($target_file);

        $alert_system = new AlertSystem(
            $notifier,
            $provider
        );
        $alert_system->send_notify('Alert!!');
    }
}
Manual Fake or Stub
• Pros
  – Fake or stub can be used as library
  – Shared implementation
• Cons
  – Different scenarios need different implementation
  – Testing class explosion
Manual Stub or Fake
• Cons
  – Need extra efforts/logics for behaviors
     • Setting return value
     • Setting thrown exception
  – Hard to validate
     • Calling sequence of functions
     • Passing arguments for functions
     • The method should be called
Test Doubles
• Using manual stub and mock
  – Is $notifier->notify() be called?
  – Does the target of $notifier->notify equal to
    expect target?
  – Does the content of $notifier->notify equal
    to expect target?
Mock objects
• Mock Objects
  – Mocks are objects pre-programmed with
    expectations, which form a specification of the
    calls they are expected to receive.
Mock Object Example
• Mock Object Example
 public function test_sendNotify_Mock_NoException() {

     $notify_content = 'fake_content';
     $mock_notifier = $this->getMock('NotifierInterface');
     $mock_notifier->expects($this->once())
                   ->method('notify')
                   ->with($this->anything(),
                          $this->equalTo($notify_content));

     $alert_system = new AlertSystem(
       $mock_notifier,
       $stub_provider
     );
     $alert_system->send_notify('Alert!!');
 }
Mock Object Example
• Mock Object Verification
  – $notifier->notify is called only once
  – $notifier->notify 1st parameter can be
    anything
  – $notifier->notify 2nd parameter should be
    equal to $notify_content
Using PHPUnit Stub
• Return Value
public function test_sendNotify_Mock_NoException() {

    $stub_provider = $this->getMock('NotifyTargetProviderInterface');
    $targets = array('hubert');
    $stub_provider->expects($this->any())
                  ->method('get_targets')
                  ->will($this->returnValue($targets));

    $alert_system = new AlertSystem(
      $mock_notifier,
      $stub_provider
    );
    $alert_system->send_notify('Alert!!');
}
Using PHPUnit Stub
• Return one of the arguments
public function testReturnArgumentStub() {
  // Create a stub for the SomeClass class.
  $stub = $this->getMock('SomeClass');

    // Configure the stub.
    $stub->expects($this->any())
         ->method('doSomething')
         ->will($this->returnArgument(0));

    // $stub->doSomething('foo') returns 'foo'
    $this->assertEquals('foo', $stub->doSomething('foo'));

    // $stub->doSomething('bar') returns 'bar'
    $this->assertEquals('bar', $stub->doSomething('bar'));
}
Using PHPUnit Stub
• Return a value from a callback
     – Useful for “out” parameter
public function testReturnCallbackStub() {
  // Create a stub for the SomeClass class.
  $stub = $this->getMock('SomeClass');

    // Configure the stub.
    $stub->expects($this->any())
         ->method('doSomething')
         ->will($this->returnCallback('str_rot13'));

    // $stub->doSomething($argument) returns str_rot13($argument)
    $this->assertEquals('fbzrguvat', $stub->doSomething('something'));
}
PHPUnit Stub
• Throw Exception
public function testThrowExceptionStub() {
  // Create a stub for the SomeClass class.
  $stub = $this->getMock('SomeClass');

    // Configure the stub.
    $stub->expects($this->any())
         ->method('doSomething')
         ->will($this->throwException(new Exception));

    // $stub->doSomething() throws Exception
    $stub->doSomething();
}
Misconception About Mocks
• Mocks are just Stubs
  – Mock is behavior verification
     • Is the function called?
     • Is the parameter passed correctly?
  – Stub is used for state verification
  – References
     • Mocks Aren’t Stubs
        – http://martinfowler.com/articles/mocksArentStubs.html
Is it HARD to use stub/mock?
• Untestable code
  – Make Your Own Dependencies
  – Heavy Duty Constructors
  – Depend on Concrete Classes
  – Use Statics
  – Using Singleton Everywhere
  – Look for Everything You Need
Dependency Injection
• Without dependency injection
  – Use “new” operator inside your class
  – Make mock object injection difficult
• Dependency Injection
  – Inject dependencies through injectors
  – Injection method
     • Constructor
     • Setter
     • Dependency Injection Framework
AlertSystem again
• AlertSystem (Hard to Test)
     – Concrete classes
     – Make Your Own Dependencies
 class AlertSystem {

     public function send_notify($content) {
       $target_provider = new FileNotifyTargetProvider('data.txt');
       $notifier = new EmailNotifier('user', 'pass', $port);

         $notify_targets = $target_provider->get_targets();
         foreach ($notify_targets as $target) {
           $notifier->notify($target, $content);
         }
     }
 }
AlertSystem constructor injection
• Constructor Injection
class AlertSystem {

     protected $_notifier;
     protected $_target_provider;

     function __construct (
         NotifierInterface $notifier,
         NotifyTargetProviderInterface $provider
     ) {
         $this->_notifier = $notifier;
         $this->_target_provider = $provider;
     }

     public function send_notify($content) {
         $notify_targets = $this->_target_provider->get_targets();
         foreach ($notify_targets as $target) {
             $this->_notifier->notify($target, $content);
         }
     }
}
Not only for testing
• Single Responsibility Principle
  – Should alert system holds notifier and data
    provider logic?
  – Ex. Should the class read registry directly?
• Dependency Inversion Principle
• Open Close Principle
The Law of Demeter
• Definition
  – Each unit should have only limited knowledge
    about other units: only units "closely" related to
    the current unit.
  – Each unit should only talk to its friends; don't talk
    to strangers.
  – Only talk to your immediate friends.
Violation of the Law
• How do you test for?
  – Mock for mock object, for another mock object
  – Like Looking for a Needle in the Haystack
  class Monitor {
    SparkPlug sparkPlug;
    Monitor(Context context) {
      this.sparkPlug = context.
        getCar().getEngine().
        getPiston().getSparkPlug();
    }
  }
Law of Demeter - Explicit
• Explicit
   – We should not need to know the details of
     collaborators
    class Mechanic {
      Engine engine;
      Mechanic(Engine engine) {
        this.engine = engine;
       }
    }
Guide – Write Testable Code
• Bad smell for non-testable Code
  – Constructor does real work
  – Digging into collaborators
  – Brittle Global State & Singletons
  – Class Does Too Much
• References
  – Guide – Write Testable Code
  – http://misko.hevery.com/attachments/Guide-
    Writing%20Testable%20Code.pdf
Conclusion
• Writing good unit tests is hard
• Good OO design brings good testability
• Using stub/mock from mocking framework
Q&A
PHPUnit Log File
• Junit Format
<testsuites>
  <testsuite name="AlertSystemTest"
file="/usr/home/hubert/own/work/trend/process/CI/php/tests/AlertSystemTe
st.php" tests="2" assertions="0" failures="1" errors="0"
time="0.031119">
    <testcase name="test_sendNotify_FakeNStub_NoException"
class="AlertSystemTest"
file="/usr/home/hubert/own/work/trend/process/CI/php/tests/AlertSystemTe
st.php" line="8" assertions="0" time="0.006881"/>
  </testsuite>
</testsuites>
PHPUnit Coverage
• PHPUnit Coverage
  – Need Xdebug
  – HTML format

Test in action week 3

  • 1.
    Test in Action– Week 3 Stub / Mock Hubert Chan
  • 2.
    Back to Basics •Wikipedia said unit testing is – A software verification and validation method in which a programmer tests if individual units of source code are fit for use.
  • 3.
    Dependency in theTest • System Under Test (SUT) Dependency – SUT need another module to perform its task • Handler need a $dbmodel to perform query • $handler = new Handler($dbmodel);
  • 4.
    Real Object isHard to Test • Real object – Supplies non-deterministic results • (e.g. the current temperature) – Difficult to create or reproduce (e.g. network fail) – Slow (e.g. database) – Does not yet exist or may change behavior
  • 5.
    Substitute Dependency • UsingFake – Fake is anything not real • Fake techniques – Mock object – Stub object – Fake object
  • 6.
    Stub Objects • StubObjects – Stubs provide canned answers to calls made during the test – Usually not responding at all to anything outside what's programmed in for the test
  • 7.
    Fake Objects • FakeObjects – Fake objects have working implementations – Usually take some shortcut, which makes them not suitable for production. – Example • An in-memory file system • An in-memory registry manager
  • 8.
  • 9.
    Example: AlertSystem • ComponentOverview – AlertSystem • Send notification to the targets, such as e-mail or SMS notifier. – NotifierInterface instance • Send actually notification to the target – NotifierTargetProviderInterface instance • Provide a target array to send notification
  • 10.
    AlertSystem Test • DependencyAnalysis – Collaboration Classes • NotifierInterface • NotifierTargetProviderInterface • Tests should – Only focus on AlertSystem – Fake the dependency
  • 11.
    Make a Fake? •FileNotifyTargetProvider class FileNotifyTargetProvider implements NotifyTargetProviderInterface { function __construct($filename) { $this->_filename = $filename; } public function get_targets() { $targets = array(); $handle = @fopen($this->_filename, "r"); while (($target = fgets($handle)) !== FALSE) { $targets[] = $target; } return $targets; } }
  • 12.
    Make a Stub? •StubNotifier class StubNotifier implements NotifierInterface { public function notify($target, $content) { } }
  • 13.
    Example: Test Code •Test Code class AlertSystemTest extends PHPUnit_Framework_TestCase { public function test_sendNotify_FakeNStub_NoException() { $target_file = __DIR__ . '/data/targets.txt'; $notifier = new StubNotifier(); $provider = new FileNotifyTargetProvider($target_file); $alert_system = new AlertSystem( $notifier, $provider ); $alert_system->send_notify('Alert!!'); } }
  • 14.
    Manual Fake orStub • Pros – Fake or stub can be used as library – Shared implementation • Cons – Different scenarios need different implementation – Testing class explosion
  • 15.
    Manual Stub orFake • Cons – Need extra efforts/logics for behaviors • Setting return value • Setting thrown exception – Hard to validate • Calling sequence of functions • Passing arguments for functions • The method should be called
  • 16.
    Test Doubles • Usingmanual stub and mock – Is $notifier->notify() be called? – Does the target of $notifier->notify equal to expect target? – Does the content of $notifier->notify equal to expect target?
  • 17.
    Mock objects • MockObjects – Mocks are objects pre-programmed with expectations, which form a specification of the calls they are expected to receive.
  • 18.
    Mock Object Example •Mock Object Example public function test_sendNotify_Mock_NoException() { $notify_content = 'fake_content'; $mock_notifier = $this->getMock('NotifierInterface'); $mock_notifier->expects($this->once()) ->method('notify') ->with($this->anything(), $this->equalTo($notify_content)); $alert_system = new AlertSystem( $mock_notifier, $stub_provider ); $alert_system->send_notify('Alert!!'); }
  • 19.
    Mock Object Example •Mock Object Verification – $notifier->notify is called only once – $notifier->notify 1st parameter can be anything – $notifier->notify 2nd parameter should be equal to $notify_content
  • 20.
    Using PHPUnit Stub •Return Value public function test_sendNotify_Mock_NoException() { $stub_provider = $this->getMock('NotifyTargetProviderInterface'); $targets = array('hubert'); $stub_provider->expects($this->any()) ->method('get_targets') ->will($this->returnValue($targets)); $alert_system = new AlertSystem( $mock_notifier, $stub_provider ); $alert_system->send_notify('Alert!!'); }
  • 21.
    Using PHPUnit Stub •Return one of the arguments public function testReturnArgumentStub() { // Create a stub for the SomeClass class. $stub = $this->getMock('SomeClass'); // Configure the stub. $stub->expects($this->any()) ->method('doSomething') ->will($this->returnArgument(0)); // $stub->doSomething('foo') returns 'foo' $this->assertEquals('foo', $stub->doSomething('foo')); // $stub->doSomething('bar') returns 'bar' $this->assertEquals('bar', $stub->doSomething('bar')); }
  • 22.
    Using PHPUnit Stub •Return a value from a callback – Useful for “out” parameter public function testReturnCallbackStub() { // Create a stub for the SomeClass class. $stub = $this->getMock('SomeClass'); // Configure the stub. $stub->expects($this->any()) ->method('doSomething') ->will($this->returnCallback('str_rot13')); // $stub->doSomething($argument) returns str_rot13($argument) $this->assertEquals('fbzrguvat', $stub->doSomething('something')); }
  • 23.
    PHPUnit Stub • ThrowException public function testThrowExceptionStub() { // Create a stub for the SomeClass class. $stub = $this->getMock('SomeClass'); // Configure the stub. $stub->expects($this->any()) ->method('doSomething') ->will($this->throwException(new Exception)); // $stub->doSomething() throws Exception $stub->doSomething(); }
  • 24.
    Misconception About Mocks •Mocks are just Stubs – Mock is behavior verification • Is the function called? • Is the parameter passed correctly? – Stub is used for state verification – References • Mocks Aren’t Stubs – http://martinfowler.com/articles/mocksArentStubs.html
  • 25.
    Is it HARDto use stub/mock? • Untestable code – Make Your Own Dependencies – Heavy Duty Constructors – Depend on Concrete Classes – Use Statics – Using Singleton Everywhere – Look for Everything You Need
  • 26.
    Dependency Injection • Withoutdependency injection – Use “new” operator inside your class – Make mock object injection difficult • Dependency Injection – Inject dependencies through injectors – Injection method • Constructor • Setter • Dependency Injection Framework
  • 27.
    AlertSystem again • AlertSystem(Hard to Test) – Concrete classes – Make Your Own Dependencies class AlertSystem { public function send_notify($content) { $target_provider = new FileNotifyTargetProvider('data.txt'); $notifier = new EmailNotifier('user', 'pass', $port); $notify_targets = $target_provider->get_targets(); foreach ($notify_targets as $target) { $notifier->notify($target, $content); } } }
  • 28.
    AlertSystem constructor injection •Constructor Injection class AlertSystem { protected $_notifier; protected $_target_provider; function __construct ( NotifierInterface $notifier, NotifyTargetProviderInterface $provider ) { $this->_notifier = $notifier; $this->_target_provider = $provider; } public function send_notify($content) { $notify_targets = $this->_target_provider->get_targets(); foreach ($notify_targets as $target) { $this->_notifier->notify($target, $content); } } }
  • 29.
    Not only fortesting • Single Responsibility Principle – Should alert system holds notifier and data provider logic? – Ex. Should the class read registry directly? • Dependency Inversion Principle • Open Close Principle
  • 30.
    The Law ofDemeter • Definition – Each unit should have only limited knowledge about other units: only units "closely" related to the current unit. – Each unit should only talk to its friends; don't talk to strangers. – Only talk to your immediate friends.
  • 31.
    Violation of theLaw • How do you test for? – Mock for mock object, for another mock object – Like Looking for a Needle in the Haystack class Monitor { SparkPlug sparkPlug; Monitor(Context context) { this.sparkPlug = context. getCar().getEngine(). getPiston().getSparkPlug(); } }
  • 32.
    Law of Demeter- Explicit • Explicit – We should not need to know the details of collaborators class Mechanic { Engine engine; Mechanic(Engine engine) { this.engine = engine; } }
  • 33.
    Guide – WriteTestable Code • Bad smell for non-testable Code – Constructor does real work – Digging into collaborators – Brittle Global State & Singletons – Class Does Too Much • References – Guide – Write Testable Code – http://misko.hevery.com/attachments/Guide- Writing%20Testable%20Code.pdf
  • 34.
    Conclusion • Writing goodunit tests is hard • Good OO design brings good testability • Using stub/mock from mocking framework
  • 35.
  • 36.
    PHPUnit Log File •Junit Format <testsuites> <testsuite name="AlertSystemTest" file="/usr/home/hubert/own/work/trend/process/CI/php/tests/AlertSystemTe st.php" tests="2" assertions="0" failures="1" errors="0" time="0.031119"> <testcase name="test_sendNotify_FakeNStub_NoException" class="AlertSystemTest" file="/usr/home/hubert/own/work/trend/process/CI/php/tests/AlertSystemTe st.php" line="8" assertions="0" time="0.006881"/> </testsuite> </testsuites>
  • 37.
    PHPUnit Coverage • PHPUnitCoverage – Need Xdebug – HTML format

Editor's Notes

  • #26 http://misko.hevery.com/2008/07/24/how-to-write-3v1l-untestable-code/
  • #27 http://tutorials.jenkov.com/dependency-injection/index.html
  • #31 https://secure.wikimedia.org/wikipedia/en/wiki/Law_of_Demeter