Test in action week 4

979 views

Published on

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

No Downloads
Views
Total views
979
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
11
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

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

×