0
Test in Action – Week 4       Good Tests      Hubert Chan
Test Lint• Test Lint  – Trustworthiness  – Maintainability  – Readability• References  – Test Lint (http://docs.typemock.c...
Trustworthy Tests• Trustworthy Tests  – Always Asserts Something  – Avoid unpredictable factor  – Don’t depend on other te...
Always Asserts Something• Always Asserts Something  – Assertion means “Verification”  – Unit Tests need to “Check Somethin...
Avoid Unpredictable Factor• Avoid Unpredictable Factor  – Unpredictable Factor     • Random Number     • Date Time  – Caus...
Avoid Unpredictable Factor• Solution  – Use Fake  – Use hard-code values  $random = rand();  $this->assertEquals(1, sut.Do...
Don’t Depend on Other Tests• Example class LogAnalyzerDependTest extends PHPUnit_Framework_TestCase {     public function ...
Don’t Depend on Other Tests• Symptom  – A test calls another tests  – It requires other tests to create/delete objects  – ...
Don’t Depend on Other Tests• Why not?  – Cannot provide explicit testing result  – Implicit tests flow  – The testA failed...
Avoid Logic in Tests• Test more than one thing  – Number of Assertion > 1  – Logics better not in tests     • switch, if, ...
Avoid Logic in Tests- Example• Test Code public function test_ImplodeAndExplode_ValidContent_CorrectResult() {   $instance...
Make Clean Tests• Change your tests  – Removing invalid tests  – Renaming / Refactoring tests  – Eliminating duplicate tests
Trustworthiness – Do it• Do it  – Testing only one thing  – Keep safe green zone     • No dependency to real database/netw...
Maintainable Tests• Maintainable Tests  – Test public function only  – Don’t Repeat Yourself     • Use Factory Function ov...
Test Public Function Only• Test Public Function Only  – Design/Program by Contract     • Private/Protected method might be...
Semantic Change• Semantic Change is really a PAIN  – API change may break all tests  – Each test need to be changed public...
Use Factory Function over Multiple           Object Creation• Use a factory function protected function create_LogAnalyzer...
Use setUp over Multiple Object                Creation• Use setUp protected function setUp() { // setUp method   $this->an...
Maintainable setUp• Maintainable setUp  – setUp() should be generic     • Cohesion     • Initialized object should be used...
Avoid Over Specification in Test• Over specified in test  – Verify internal state/behavior of object  – Using mocks when s...
Verify internal state/behavior of object• Solution  – Never verify internal state/behavior  – Maybe no need to test  publi...
Avoid Multiple Asserts• Why not?  – Assertion failure will throw exception. Multiple    assertion cannot get all failure p...
Data Provider Sample• Test Codeclass DataTest extends PHPUnit_Framework_TestCase {  /**  * @dataProvider provider  */  pub...
Readable Tests•   Test Naming•   Variable Naming•   Good Assert Message•   Separate Arrange and Assertion•   Mock and Stub...
Test Naming• Function Name  – Test function name should be    test_<function>_<scenario>_<expect_behavior>  – Example    •...
Variable Name• Avoid Hard Code in tests public function test BadlyNamedTest() {   $log = new LogAnalyzer();   $result= log...
Good Assertion Message• Good Assertion Message  – Don’t repeat what the built-in test framework    outputs to the console....
Separate Arrange and Assertion• Separate Arrange and Assertion public function test_BadAssertMessage() {   $this->assertEq...
Mock and Stub Naming• Include “mock” and “stub” in variable name public function test_sendNotify_Mock_NoException() {     ...
Q&A
PHPUnit and Selenium• Use PHPUnit to do  – Integration Test  – Acceptance Test• References  – PHPUnit Selenium     • http:...
PHPUnit and Selenium• Use PHPUnit and Seleniumclass WebTest extends PHPUnit_Extensions_SeleniumTestCase {  protected funct...
PHPUnit and Selenium
Upcoming SlideShare
Loading in...5
×

Test in action week 4

763

Published on

Published in: Technology, Business
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
763
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
11
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Transcript of "Test in action week 4"

  1. 1. Test in Action – Week 4 Good Tests Hubert Chan
  2. 2. Test Lint• Test Lint – Trustworthiness – Maintainability – Readability• References – Test Lint (http://docs.typemock.com/lint/ )
  3. 3. Trustworthy Tests• Trustworthy Tests – Always Asserts Something – Avoid unpredictable factor – Don’t depend on other tests – Avoid Logic in Tests
  4. 4. Always Asserts Something• Always Asserts Something – Assertion means “Verification” – Unit Tests need to “Check Something”• Exceptions – Check exception not thrown • Name “Login_Call_NoExceptionThrown” – Specified Mock Object
  5. 5. Avoid Unpredictable Factor• Avoid Unpredictable Factor – Unpredictable Factor • Random Number • Date Time – Cause • Unreliable/Inconsistent Result • Hard to write Assertion statement
  6. 6. Avoid Unpredictable Factor• Solution – Use Fake – Use hard-code values $random = rand(); $this->assertEquals(1, sut.DoSomething($random)); $pseudoRandom = 1234; $this->assertEquals(1, sut.DoSomething(pseudoRandom));
  7. 7. Don’t Depend on Other Tests• Example class LogAnalyzerDependTest extends PHPUnit_Framework_TestCase { public function test_LogAnalyzerDepend_Construct_NoException() { $this->analyzer = new LogAnalyzerDepend(); $this->analyzer->initialize(); } public function test_IsValid_InValidContent_ReturnFalse() { $this->test_LogAnalyzerDepend_Construct_NoException(); $this->assertFalse($this->analyzer->is_valid(abc)); } }
  8. 8. Don’t Depend on Other Tests• Symptom – A test calls another tests – It requires other tests to create/delete objects – A test depends on system state set by other tests – Test order matters
  9. 9. Don’t Depend on Other Tests• Why not? – Cannot provide explicit testing result – Implicit tests flow – The testA failed because callee testB failed• Solution – Extract reused code to utility – For create/delete object, use “setUp” and “tearDown” instead
  10. 10. Avoid Logic in Tests• Test more than one thing – Number of Assertion > 1 – Logics better not in tests • switch, if, or else statement • foreach, for, or while loops
  11. 11. Avoid Logic in Tests- Example• Test Code public function test_ImplodeAndExplode_ValidContent_CorrectResult() { $instance = new MoreThanOne(); $test_array = array(1, 2, 3); $test_string = 1,2,3; for ($i = 0; $i < 2; $i++) { if ($i === 0) { // Test explode2 $result = $instance->explode2(,, $test_string); $this->assertEquals($test_array, $result); } elseif ($i === 1) { // Test implode2 $result = $instance->implode2(,, $test_array); $this->assertEquals($test_string, $result); } } }
  12. 12. Make Clean Tests• Change your tests – Removing invalid tests – Renaming / Refactoring tests – Eliminating duplicate tests
  13. 13. Trustworthiness – Do it• Do it – Testing only one thing – Keep safe green zone • No dependency to real database/network • Keep result consistent – Assuring code coverage – Attitude • Add a unit test for newly tickets/trackers
  14. 14. Maintainable Tests• Maintainable Tests – Test public function only – Don’t Repeat Yourself • Use Factory Function over Multiple Object Creation • Use setUp – Using setUp in a maintainable manner – Avoid Over Specification in Tests – Avoid multiple asserts
  15. 15. Test Public Function Only• Test Public Function Only – Design/Program by Contract • Private/Protected method might be changed – Extract private/protected function to new class • Adopt Single Responsibility Principle (SRP)
  16. 16. Semantic Change• Semantic Change is really a PAIN – API change may break all tests – Each test need to be changed public function test_IsValid_InValidContent_ReturnFalse_New() { $analyzer = new LogAnalyzer(); $analyzer->initialize(); // new requirement $this->assertFalse($analyzer->is_valid(abc)); }
  17. 17. Use Factory Function over Multiple Object Creation• Use a factory function protected function create_LogAnalyzer() { // Factory Method $analyzer = new LogAnalyzer(); $analyzer->initialize(); // New API handled here return $analyzer; } public function test_IsValid_InValidContent_ReturnFalse() { $analyzer = $this->create_LogAnalyzer(); // Use factory $this->assertFalse($analyzer->is_valid(abc)); }
  18. 18. Use setUp over Multiple Object Creation• Use setUp protected function setUp() { // setUp method $this->analyzer = new LogAnalyzer(); $this->analyzer->initialize(); // New API handled here } public function test_IsValid_InValidContent_ReturnFalse() { $this->assertFalse($this->analyzer->is_valid(abc)); } public function test_IsValid_ValidContent_ReturnFalse() { $this->assertTrue($this->analyzer->is_valid(valid)); }
  19. 19. Maintainable setUp• Maintainable setUp – setUp() should be generic • Cohesion • Initialized object should be used in all tests • Might not be appropriate to arrange mock/stub in setUp() – setUp() should be kept his readability
  20. 20. Avoid Over Specification in Test• Over specified in test – Verify internal state/behavior of object – Using mocks when stubs are enough – A test assumes specific order or exact string matches when it isn’t required.
  21. 21. Verify internal state/behavior of object• Solution – Never verify internal state/behavior – Maybe no need to test public function test_Initialize_WhenCalled_SetsDefaultDelimiterIsTabDelimiter(){ $analyzer = new LogAnalyzer(); $this->assertEquals(null, $analyzer->GetInternalDefaultDelimiter() ); $analyzer->Initialize(); $this->assertEquals(t, $analyzer->GetInternalDefaultDelimiter() ); }
  22. 22. Avoid Multiple Asserts• Why not? – Assertion failure will throw exception. Multiple assertion cannot get all failure point at once – Test multiple thing in one tests• Solution – Separate tests for different assertion – Use data provider / parameter tests
  23. 23. Data Provider Sample• Test Codeclass DataTest extends PHPUnit_Framework_TestCase { /** * @dataProvider provider */ public function testAdd($a, $b, $c) { $this->assertEquals($c, $a + $b); } public function provider() { return array( array(0, 0, 0), array(0, 1, 1), array(1, 0, 1), array(1, 1, 3) ); }}
  24. 24. Readable Tests• Test Naming• Variable Naming• Good Assert Message• Separate Arrange and Assertion• Mock and Stub Naming
  25. 25. Test Naming• Function Name – Test function name should be test_<function>_<scenario>_<expect_behavior> – Example • test_escape_evenBackSlashesData_successEscape
  26. 26. Variable Name• Avoid Hard Code in tests public function test BadlyNamedTest() { $log = new LogAnalyzer(); $result= log.GetLineCount("abc.txt"); $this->assertEquals(-100, result); } public function test WellNamedTest() { $log = new LogAnalyzer(); $COULD_NOT_READ_FILE = -100; $result= log.GetLineCount("abc.txt"); $this->assertEquals($COULD_NOT_READ_FILE, result); }
  27. 27. Good Assertion Message• Good Assertion Message – Don’t repeat what the built-in test framework outputs to the console. – Don’t repeat what the test name explains. – If you don’t have anything good to say, don’t say anything. – Write what should have happened or what failed
  28. 28. Separate Arrange and Assertion• Separate Arrange and Assertion public function test_BadAssertMessage() { $this->assertEquals(COULD_NOT_READ_FILE, log->GetLineCount("abc.txt") ); } public function test_GoodAssertMessage() { $result = log->GetLineCount("abc.txt"); $this->assertEquals($COULD_NOT_READ_FILE, $result); }
  29. 29. Mock and Stub Naming• Include “mock” and “stub” in variable name 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!!); }
  30. 30. Q&A
  31. 31. PHPUnit and Selenium• Use PHPUnit to do – Integration Test – Acceptance Test• References – PHPUnit Selenium • http://www.phpunit.de/manual/current/en/selenium.h tml • http://seleniumhq.org/documentation/
  32. 32. PHPUnit and Selenium• Use PHPUnit and Seleniumclass WebTest extends PHPUnit_Extensions_SeleniumTestCase { protected function setUp() { $this->setBrowser(*firefox); $this->setBrowserUrl(http://www.example.com/); } public function testTitle() { $this->open(http://www.example.com/); $this->assertTitle(Example WWW Page); }}
  33. 33. PHPUnit and Selenium
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×