• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Test in action   week 3
 

Test in action week 3

on

  • 1,594 views

 

Statistics

Views

Total Views
1,594
Views on SlideShare
1,594
Embed Views
0

Actions

Likes
2
Downloads
5
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

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.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • http://misko.hevery.com/2008/07/24/how-to-write-3v1l-untestable-code/
  • http://tutorials.jenkov.com/dependency-injection/index.html
  • https://secure.wikimedia.org/wikipedia/en/wiki/Law_of_Demeter

Test in action   week 3 Test in action week 3 Presentation Transcript

  • 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 whats 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?• FileNotifyTargetProviderclass 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?• StubNotifierclass StubNotifier implements NotifierInterface { public function notify($target, $content) { }}
  • Example: Test Code• Test Codeclass 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 Valuepublic 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 argumentspublic 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” parameterpublic 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 Exceptionpublic 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 Injectionclass 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; dont 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/AlertSystemTest.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/AlertSystemTest.php" line="8" assertions="0" time="0.006881"/> </testsuite></testsuites>
  • PHPUnit Coverage• PHPUnit Coverage – Need Xdebug – HTML format