Test in action   week 3
Upcoming SlideShare
Loading in...5
×

Like this? Share it with your network

Share
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
1,732
On Slideshare
1,732
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
6
Comments
0
Likes
2

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide
  • 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

Transcript

  • 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 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);
  • 4. 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
  • 5. Substitute Dependency• Using Fake – Fake is anything not real• Fake techniques – Mock object – Stub object – Fake object
  • 6. 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
  • 7. 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
  • 8. Example: AlertSystem
  • 9. 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
  • 10. AlertSystem Test• Dependency Analysis – Collaboration Classes • NotifierInterface • NotifierTargetProviderInterface• Tests should – Only focus on AlertSystem – Fake the dependency
  • 11. 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; }}
  • 12. Make a Stub?• StubNotifierclass StubNotifier implements NotifierInterface { public function notify($target, $content) { }}
  • 13. 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!!); }}
  • 14. Manual Fake or Stub• Pros – Fake or stub can be used as library – Shared implementation• Cons – Different scenarios need different implementation – Testing class explosion
  • 15. 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
  • 16. 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?
  • 17. Mock objects• Mock Objects – 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 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!!);}
  • 21. 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));}
  • 22. 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));}
  • 23. 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();}
  • 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 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
  • 26. 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
  • 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 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); } }}
  • 29. 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
  • 30. 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.
  • 31. 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(); } }
  • 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 – 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
  • 34. Conclusion• Writing good unit tests is hard• Good OO design brings good testability• Using stub/mock from mocking framework
  • 35. Q&A
  • 36. 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>
  • 37. PHPUnit Coverage• PHPUnit Coverage – Need Xdebug – HTML format