Fundamentals of unit testing in PHP usingPHPUnit<br />Nicolas A. Bérard-Nault<br />5 May 2011<br />
Some of the goals of test automation<br />For the stakeholders:<br /><ul><li>Improvingexternalqualityby reducingdefectdensity
Improvinginternalqualityby increasingmaintainability
Reduced short and long-termrisk</li></ul>For the programmers:<br /><ul><li>Facilitatingdefectlocalization
Use tests as documentation
Use tests as a specification</li></li></ul><li>The automatedtesting continuum<br />Integration tests<br />Unit tests<br />...
PHPUnit and the xUnitfamily<br /><ul><li>Written by Sebastian Bergmann
Member of the xUnitfamily
Direct descendant of sUnitwritten by Kent Beck and jUnit, written by Beck and Erich Gamma</li></ul>Website: http://www.php...
Your first <br />PHPUnittest (1)<br />Goal: test an implementation of ROT13<br />System under test:<br />functionrot13($te...
Your first <br />PHPUnittest (2)<br />Class namehas Test suffix<br />Base class for tests<br />class Rot13Test extendsPHPU...
Your first <br />PHPUnittest (3)<br />nicobn@nicobn-laptop:~$ phpunit rot13.php<br />PHPUnit 3.5.5 by Sebastian Bergmann.<...
Preconditions, invariants and postconditions<br />functionrot13($text)<br />{<br />$len = strlen($text);<br />for ($i = 0;...
NEWFLASH: It’s not a question of how awesomelyawesome of a programmer you are, but a question of methodology !<br />Sad pa...
Test first ! (1)<br />“Applying ROT13 to a piece of text merely requires examining its alphabetic characters and replacing...
Test first ! (2a)<br />functionrot13($text)<br />{<br />}<br />class Rot13Test extendsPHPUnit_Framework_TestCase<br />{<br...
Test first ! (2b)<br />functionrot13($text)<br />{<br />return‘n’;<br />}<br />class Rot13Test extendsPHPUnit_Framework_Te...
Test first ! (2c)<br />functionrot13($text)<br />{<br />returnchr(ord($text{0}) + 13);<br />}<br />class Rot13Test extends...
Test first ! (3a)<br />functionrot13($text)<br />{<br />returnchr(ord($text{0}) + 13);<br />}<br />class Rot13Test extends...
Test first ! (3b)<br />functionrot13($text)<br />{<br />return chr((ord($text{0}) - ord('a') + 13) % 26 + ord('a'));<br />...
Test first ! (4a)<br />functionrot13($text)<br />{<br />   return chr((ord($text{0}) - ord('a') + 13) % 26 + ord('a'));<br...
Test first ! (4b)<br />functionrot13($text)<br />{<br />if (!ctype_alnum($text{0})) {<br />return$text{0};<br />    }<br /...
Test first ! (5a)<br />functionrot13($text)<br />{<br />if (!ctype_alnum($text{0})) {<br />return$text{0};<br />    }<br /...
Test first ! (5b)<br />functionrot13($text)<br />{<br />if (!ctype_alnum($text{0})) {<br />return$text{0};<br />    }<br /...
Test first ! (6a)<br />functionrot13($text)<br />{<br />if (!ctype_alnum($text{0})) {<br />return$text{0};<br />    }<br /...
Test first ! (6b)<br />functionrot13($text)<br />{<br />$str = '';<br />$len = strlen($text);<br />for ($i = 0; $i < $len;...
Test-drivendevelopment<br />RED<br />GREEN<br />REFACTOR<br />
PHPUnit assertions<br />Note: most assertions have a assertNotXXXX() counterpart.<br />
Test status<br />Do yourself and yourcolleaguesa favor and mark tests as skipped or incompletewhen relevant !<br />
Upcoming SlideShare
Loading in...5
×

Unit Testing Presentation

693

Published on

Published in: Technology, Education
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
693
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
13
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Unit Testing Presentation

  1. 1. Fundamentals of unit testing in PHP usingPHPUnit<br />Nicolas A. Bérard-Nault<br />5 May 2011<br />
  2. 2. Some of the goals of test automation<br />For the stakeholders:<br /><ul><li>Improvingexternalqualityby reducingdefectdensity
  3. 3. Improvinginternalqualityby increasingmaintainability
  4. 4. Reduced short and long-termrisk</li></ul>For the programmers:<br /><ul><li>Facilitatingdefectlocalization
  5. 5. Use tests as documentation
  6. 6. Use tests as a specification</li></li></ul><li>The automatedtesting continuum<br />Integration tests<br />Unit tests<br />Functional tests<br />« Black box »<br />$$$<br />Slow<br />Functionality<br />« White box »<br />$<br />Fast<br />Code<br />Programmers are definitelyresponsible for these tests<br />QA is (usually) responsible for these tests<br />
  7. 7. PHPUnit and the xUnitfamily<br /><ul><li>Written by Sebastian Bergmann
  8. 8. Member of the xUnitfamily
  9. 9. Direct descendant of sUnitwritten by Kent Beck and jUnit, written by Beck and Erich Gamma</li></ul>Website: http://www.phpunit.de<br />Code coverageisprovidedusing the xDebug extension: http://www.xdebug.org<br />
  10. 10. Your first <br />PHPUnittest (1)<br />Goal: test an implementation of ROT13<br />System under test:<br />functionrot13($text)<br />{<br />$len = strlen($text);<br />for ($i = 0; $i < $len; $i++)<br /> {<br />$text{$i} = chr((ord($text{$i}) - ord('a') + 13) % 26 + ord('a'));<br /> }<br />return$text;<br />}<br />Initial naïve approach: Formulateexpectedbehavior<br />
  11. 11. Your first <br />PHPUnittest (2)<br />Class namehas Test suffix<br />Base class for tests<br />class Rot13Test extendsPHPUnit_Framework_TestCase<br />{<br />public functiontestWord()<br /> {<br />$this->assertEquals('cheryl', rot13('purely'));<br /> }<br />}<br />Test methodhas test prefix<br />Post-condition verification<br />
  12. 12. Your first <br />PHPUnittest (3)<br />nicobn@nicobn-laptop:~$ phpunit rot13.php<br />PHPUnit 3.5.5 by Sebastian Bergmann.<br />.<br />Time: 0 seconds, Memory: 3.50Mb<br />OK (1 test, 1 assertion)<br />The test passes but have wereallycovered all of our bases ?<br />
  13. 13. Preconditions, invariants and postconditions<br />functionrot13($text)<br />{<br />$len = strlen($text);<br />for ($i = 0; $i < $len; $i++)<br /> {<br />$text{$i} = chr((ord($text{$i}) - ord('a') + 13) % 26 + ord('a'));<br /> }<br />return$text;<br />}<br />Precondition: $text must be a string<br />Precondition: $text must belower case<br />Invariant: non-alpha characters must remainunchanged<br />Postcondition: each alpha character must bemoved 13 positions <br />Wescrewed up ! How many more tests do weneed ? <br />
  14. 14. NEWFLASH: It’s not a question of how awesomelyawesome of a programmer you are, but a question of methodology !<br />Sad panda issad<br />
  15. 15. Test first ! (1)<br />“Applying ROT13 to a piece of text merely requires examining its alphabetic characters and replacing each one by the letter 13 places further along in the alphabet, wrapping back to the beginning if necessary. A becomes N, B becomes O, and so on up to M, which becomes Z, then the sequence continues at the beginning of the alphabet: N becomes A, O becomes B, and so on to Z, which becomes M. Only those letters which occur in the English alphabet are affected; numbers, symbols, whitespace, and all other characters are left unchanged. Because there are 26 letters in the English alphabet and 26 = 2 × 13, the ROT13 function is its own inverse.”<br />(Wikipedia)<br />
  16. 16. Test first ! (2a)<br />functionrot13($text)<br />{<br />}<br />class Rot13Test extendsPHPUnit_Framework_TestCase<br />{<br />public function test_A_Lower()<br /> {<br />$this->assertEquals('n', rot13('a'));<br /> }<br />}<br />There was 1 failure:<br />1) Rot13Test::test_A_Lower<br />Failed asserting that two strings are equal.<br />--- Expected<br />+++ Actual<br />@@ @@<br />-n<br />+<br />
  17. 17. Test first ! (2b)<br />functionrot13($text)<br />{<br />return‘n’;<br />}<br />class Rot13Test extendsPHPUnit_Framework_TestCase<br />{<br />public function test_A_Lower()<br /> {<br />$this->assertEquals('n', rot13('a'));<br /> }<br />}<br />PHPUnit 3.5.5 by Sebastian Bergmann.<br />.<br />Time: 1 second, Memory: 3.50Mb<br />OK (1 test, 1 assertion)<br />
  18. 18. Test first ! (2c)<br />functionrot13($text)<br />{<br />returnchr(ord($text{0}) + 13);<br />}<br />class Rot13Test extendsPHPUnit_Framework_TestCase<br />{<br />public function test_A_Lower()<br /> {<br />$this->assertEquals('n', rot13('a'));<br /> }<br />}<br />PHPUnit 3.5.5 by Sebastian Bergmann.<br />.<br />Time: 1 second, Memory: 3.50Mb<br />OK (1 test, 1 assertion)<br />
  19. 19. Test first ! (3a)<br />functionrot13($text)<br />{<br />returnchr(ord($text{0}) + 13);<br />}<br />class Rot13Test extendsPHPUnit_Framework_TestCase<br />{<br />public function test_A_Lower()<br /> {<br />$this->assertEquals('n', rot13('a'));<br /> }<br />public function test_N_Lower()<br /> {<br />$this->assertEquals(‘a', rot13(‘n'));<br /> }<br />}<br />FAIL !<br />
  20. 20. Test first ! (3b)<br />functionrot13($text)<br />{<br />return chr((ord($text{0}) - ord('a') + 13) % 26 + ord('a'));<br />}<br />class Rot13Test extendsPHPUnit_Framework_TestCase<br />{<br />public function test_A_Lower()<br /> {<br />$this->assertEquals('n', rot13('a'));<br /> }<br />public function test_N_Lower()<br /> {<br />$this->assertEquals(‘a', rot13(‘n'));<br /> }<br />}<br />PASS !<br />
  21. 21. Test first ! (4a)<br />functionrot13($text)<br />{<br /> return chr((ord($text{0}) - ord('a') + 13) % 26 + ord('a'));<br />}<br />class Rot13Test extendsPHPUnit_Framework_TestCase<br />{<br />public function test_A_Lower()<br /> {<br />$this->assertEquals('n', rot13('a'));<br /> }<br />public function test_N_Lower()<br /> {<br />$this->assertEquals(‘a', rot13(‘n'));<br /> }<br />public functiontest_Symbol()<br /> {<br />$this->assertEquals('$', rot13('$'));<br /> }<br />}<br />FAIL !<br />
  22. 22. Test first ! (4b)<br />functionrot13($text)<br />{<br />if (!ctype_alnum($text{0})) {<br />return$text{0};<br /> }<br /> return chr((ord($text{0}) - ord('a') + 13) % 26 + ord('a'));<br />}<br />class Rot13Test extendsPHPUnit_Framework_TestCase<br />{<br />public function test_A_Lower()<br /> {<br />$this->assertEquals('n', rot13('a'));<br /> }<br />public function test_N_Lower()<br /> {<br />$this->assertEquals(‘a', rot13(‘n'));<br /> }<br />public functiontest_Symbol()<br /> {<br />$this->assertEquals('$', rot13('$'));<br /> }<br />}<br />PASS !<br />
  23. 23. Test first ! (5a)<br />functionrot13($text)<br />{<br />if (!ctype_alnum($text{0})) {<br />return$text{0};<br /> }<br /> return chr((ord($text{0}) - ord('a') + 13) % 26 + ord('a'));<br />}<br />class Rot13Test extendsPHPUnit_Framework_TestCase<br />{<br />/* […] */<br />public functiontest_N_Upper()<br /> {<br />$this->assertEquals('A', rot13('N'));<br /> }<br />}<br />FAIL !<br />
  24. 24. Test first ! (5b)<br />functionrot13($text)<br />{<br />if (!ctype_alnum($text{0})) {<br />return$text{0};<br /> }<br />if (ctype_upper($text{0})) {<br />$delta = ord('A');<br /> } else {<br />$delta = ord('a');<br /> }<br /> return chr((ord($text{0}) - $delta + 13) % 26 + $delta);<br />}<br />class Rot13Test extendsPHPUnit_Framework_TestCase<br />{<br />/* […] */<br />public functiontest_N_Upper()<br /> {<br />$this->assertEquals('A', rot13('N'));<br /> }<br />}<br />PASS !<br />
  25. 25. Test first ! (6a)<br />functionrot13($text)<br />{<br />if (!ctype_alnum($text{0})) {<br />return$text{0};<br /> }<br />if (ctype_upper($text{0})) {<br />$delta = ord('A');<br /> } else {<br />$delta = ord('a');<br /> }<br /> return chr((ord($text{0}) - $delta + 13) % 26 + $delta);<br />}<br />class Rot13Test extendsPHPUnit_Framework_TestCase<br />{<br />/* […] */<br />public functiontest_N_Purely()<br /> {<br />$this->assertEquals(‘$purely$', rot13(‘$cheryl$'));<br /> }<br />}<br />FAIL !<br />
  26. 26. Test first ! (6b)<br />functionrot13($text)<br />{<br />$str = '';<br />$len = strlen($text);<br />for ($i = 0; $i < $len; $i++)<br /> {<br />if (!ctype_alnum($text{$i})) {<br />$str .= $text{$i};<br /> } else {<br /> if (ctype_upper($text{$i})) {<br />$delta = ord('A');<br /> } else {<br />$delta = ord('a');<br /> }<br />$str.= chr((ord($text{$i}) - $delta + 13) % 26 + $delta);<br /> }<br /> }<br />return$str;<br />}<br />PASS !<br />
  27. 27. Test-drivendevelopment<br />RED<br />GREEN<br />REFACTOR<br />
  28. 28. PHPUnit assertions<br />Note: most assertions have a assertNotXXXX() counterpart.<br />
  29. 29. Test status<br />Do yourself and yourcolleaguesa favor and mark tests as skipped or incompletewhen relevant !<br />
  30. 30. Anatomy of a<br />unit test<br />SETUP: Create the fixture<br />EXERCISE: Execute the system under test (SUT)<br />VERIFY: Check expectations (state mutations, output, invariants, etc.)<br />TEAR DOWN: Clean the fixture<br />
  31. 31. Whatis a good tests<br /><ul><li>Deterministic
  32. 32. FULLY automated
  33. 33. Self-checking
  34. 34. Simple, robust
  35. 35. Expressive
  36. 36. Should not harm the developmentprocess in the long run</li></ul>Tests, if usedincorrectly, canbedetrimental to a project<br />
  37. 37. Principles of test automation<br />1) INDEPENDANCE: A test should not interactwithanother test (shared mutable state). <br />2) NO TEST CODE IN PRODUCTION: Ban if ($test). Don’teventhink about it.<br />3) ISOLATION: Each SUT must beindependant. State mutations duringexerciseshould<br />onlyoccur in and by the SUT.<br />4) D.R.Y.: Do not repeatyourself. Valid for fixture setup as well as test overlap.<br />5) CLEAR INTENTIONS: A test shouldbe simple and clearlycommunicateits scope.<br />6) MINIMIZE UNTESTABLE CODE: Sorry, please replace minimize by eliminate.<br />7) TEST FIRST: Preventsmostsmells, ensureshighcoverage, providesimmediate feedback.<br />8) DO NOT TEST YOUR PRIVATES: The need to test a privatemethodis a symptom of a deeperproblem.<br />
  38. 38. Exempligratia<br />Symfony2’s routing component:<br />https://github.com/symfony/symfony/blob/master/tests/Symfony/Tests/Component/Routing/Matcher/UrlMatcherTest.php<br />Example of a feeble test (objectcreation code repeated), long test (testMatch).<br />Symfony2’s DOM Crawler:<br />https://github.com/symfony/symfony/blob/master/tests/Symfony/Tests/Component/DomCrawler/CrawlerTest.php<br />Example of utility methods (at the bottom), @covers, SUT factorymethod (createTestCrawler). <br />Symfony2’s HttpKernel component:<br />https://github.com/symfony/symfony/blob/master/tests/Symfony/Tests/Component/HttpKernel/KernelTest.php<br />Example of test doubles.<br />
  39. 39. Resources<br />The seminal book on unit testing. Written by Gerard Meszaros.<br />ISBN-13: 978-0131495050<br />
  1. A particular slide catching your eye?

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

×