Unit Testing: First Steps

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

0 comments

Post a comment

    Post a comment
    Embed Video
    Edit your comment Cancel

    1 Favorite

    Unit Testing: First Steps - Presentation Transcript

    1. Unit Testing First Steps Jakob Heuser http://www.slideshare.net/jakobo
    2. Who? • 10 years in the industry • Academic Skills Achievement Program • Homeland Security Digital Library • Gaia Online • LinkedIn
    3. Who?
    4. Who?
    5. Who?
    6. Who?
    7. Our Goal • Break down testing myths • Grasp testing (the concept) • See a few tests • Walk out wanting to write some tests
    8. Covering • Intro • Simple Tests • Frameworks • Darts • Advocacy This is some code This is a passing test This is a failing test
    9. Unit Testing Is • Easier than you think • Probably harder than it should be • An idea not a software package • (though there is software for it)
    10. Unit • Smallest testable part of an application
    11. Unit • Smallest testable part of an application • Function (or)
    12. Unit • Smallest testable part of an application • Function (or) • Public method (or)
    13. Unit • Smallest testable part of an application • Function (or) • Public method (or) • Included file
    14. Unit Testing Concept • Given X and Y, Z should happen • Make changes to your code • Given X and Y, Z should still happen
    15. Testing Requirements not the Code
    16. Testing Requirements? • Requirements define code • Serve as documentation for the code alongside the code itself
    17. A Very Basic Test <?PHP function addLineBreaks($in_string) { $in_string = str_replace("n", "n<br/>"); return $in_string; }
    18. A Very Basic Test <?PHP function addLineBreaks($in_string) { $in_string = str_replace("n", "n<br/>"); return $in_string; } <?PHP $str = "This isna test"; echo "nn===n"; echo addLineBreaks($str); echo "n===nn";
    19. Visual Inspection • This is a “test” • Quick to write and verify
    20. I Can’t Do That For EVERYTHING!
    21. What If... • we had hundreds of tests • we didn’t have time to visually inspect output • we could describe what we want programatically
    22. Solutions?
    23. Testing Frameworks • Condense our “testing” process • Tell us what went wrong, and why • Automated
    24. Testing Frameworks • SnapTest (snaptest.net) • PHPUnit (phpunit.de) • SimpleTest (simpletest.org) • Testilence (testilence.org) • (some MVC frameworks have testing)
    25. Testing Frameworks • Every framework has different goals • Find what’s right for you and your project
    26. SnapTest (5)
    27. SnapTest • Simplify the testing process • Lower barrier to entry (at cost of doing it “all”) • Run in any environment including via web
    28. PHPUnit (4, 5)
    29. PHPUnit • Can test pretty much anything • Most established project • Test coverage analysis with XDebug
    30. SimpleTest (4, 5)
    31. SimpleTest • Web test runner support • Very small footprint • Simulate browser events
    32. Testilence (5)
    33. Testilence • PHP 5 targeted • C shell runner “tence”
    34. So Which One? • Examples tonight use SnapTest • Focus on the theory
    35. The Game of Darts
    36. The Rules of Darts • Start at 501 points • Goal is to reach 0 points • 3 throws results in a score • Must finish on 0 exactly
    37. Our Code <?PHP class DartsGame { Score starts protected $score; at 501 public function __construct() { $this->score = 501; } public function throwDart($score) { if ($this->score - $score < 0) { return $this->score; } $this->score = $this->score - $score; return $this->score; } public function getScore() { return $this->score; } }
    38. Our Code <?PHP class DartsGame { protected $score; public function __construct() { $this->score = 501; } Throw a public function throwDart($score) { if ($this->score - $score < 0) { dart return $this->score; } $this->score = $this->score - $score; return $this->score; } public function getScore() { return $this->score; } }
    39. Our Code <?PHP class DartsGame { protected $score; public function __construct() { $this->score = 501; } public function throwDart($score) { if ($this->score - $score < 0) { return $this->score; } $this->score = $this->score - $score; Save new } return $this->score; score public function getScore() { return $this->score; } }
    40. Our Code <?PHP class DartsGame { protected $score; public function __construct() { $this->score = 501; } public function throwDart($score) { if ($this->score - $score < 0) { return $this->score; } $this->score = $this->score - $score; return $this->score; } public function getScore() { } return $this->score; Get the } current score
    41. Our First Test • A new game • Score should be 501
    42. Our First Test <?PHP require_once 'basedarts.php'; class New_Game_No_Throws extends Snap_UnitTestCase { public function setUp() { $this->Darts = new DartsGame(); } public function tearDown() { unset($this->Darts); } public function testScoreIsFiveHundredOne() { return $this->assertEqual($this->Darts->getScore(), 501); } }
    43. Our Results jakobo@Hikaru ~/Dropbox/2009-06-18 unittesting/resources> snaptest.sh ./ . ______________________________________________________________________ Total Cases: 1 Total Tests: 1 Total Pass: 1 Total Defects: 0 Total Failures: 0 Total Skips: 0 Total Todo: 0
    44. Our Second Test • A new game • Throw 10, 0, 0 • Score should be 491
    45. Our Test <?PHP require_once 'basedarts.php'; class Throw_Ten_Zero_Zero_Test extends Snap_UnitTestCase { Throw some public function setUp() { darts $this->Darts = new DartsGame(); $this->Darts->throwDart(10); $this->Darts->throwDart(0); $this->Darts->throwDart(0); } public function tearDown() { unset($this->Darts); } public function testScoreIsFourNinteyOne() { return $this->assertEqual($this->Darts->getScore(), 491); } }
    46. Our Test <?PHP require_once 'basedarts.php'; class Throw_Ten_Zero_Zero_Test extends Snap_UnitTestCase { public function setUp() { $this->Darts = new DartsGame(); $this->Darts->throwDart(10); $this->Darts->throwDart(0); $this->Darts->throwDart(0); Reset dart game } when done public function tearDown() { unset($this->Darts); } public function testScoreIsFourNinteyOne() { return $this->assertEqual($this->Darts->getScore(), 491); } }
    47. Our Test <?PHP require_once 'basedarts.php'; class Throw_Ten_Zero_Zero_Test extends Snap_UnitTestCase { public function setUp() { $this->Darts = new DartsGame(); $this->Darts->throwDart(10); $this->Darts->throwDart(0); $this->Darts->throwDart(0); } public function tearDown() { unset($this->Darts); } The Test public function testScoreIsFourNinteyOne() { return $this->assertEqual($this->Darts->getScore(), 491); } }
    48. Our Results jakobo@Hikaru ~/Dropbox/2009-06-18 unittesting/resources> snaptest.sh ./ .. ______________________________________________________________________ Total Cases: 2 Total Tests: 2 Total Pass: 2 Total Defects: 0 Total Failures: 0 Total Skips: 0 Total Todo: 0 Okay, is this working?
    49. Sanity Check <?PHP class DartsGame { protected $score; public function __construct() { $this->score = 501; } Broken in a very public function throwDart($score) { obvious way if ($this->score - $score < 0) { return $this->score; } $this->score = 0; return $this->score; } public function getScore() { return $this->score; } }
    50. Predictable Failure jakobo@Hikaru ~/Dropbox/2009-06-18 unittesting/resources> snaptest.sh ./ .F Equal (==) assertion failed. [int(491) != int(0)] in method: testScoreIsFourNinteyOne in class: Throw_Ten_Zero_Zero_Test in file: /Users/jakobo/Dropbox/2009-06-18 unittesting/resources/ basedarts.stest.php ______________________________________________________________________ Total Cases: 2 Total Tests: 2 Total Pass: 1 Total Defects: 0 Total Failures: 1 Total Skips: 0 Total Todo: 0
    51. Back to our Rules • Start at 501 points • Goal is to reach 0 points • 3 throws results in a score • Must finish on 0 exactly
    52. The Next Test <?PHP require_once 'basedarts.php'; class Throw_Last_Set_Over_501_Test extends Snap_UnitTestCase { public function setUp() { $this->Darts = new DartsGame(); $this->Darts->throwDart(50); // down by 450 (51 left, next block shouldn’t score) $this->Darts->throwDart(50); $this->Darts->throwDart(50); $this->Darts->throwDart(1); } // ... public function testScoreIsFiftyOne() { return $this->assertEqual($this->Darts->getScore(), 51); } }
    53. Huh... jakobo@Hikaru ~/Dropbox/2009-06-18 unittesting/resources> snaptest.sh ./ .F. Equal (==) assertion failed. [int(51) != int(0)] in method: testScoreIsFiftyOne in class: Throw_Last_Set_Over_501_Test in file: /Users/jakobo/Dropbox/2009-06-18 unittesting/resources/ basedarts_overage.stest.php ______________________________________________________________________ Total Cases: 3 Total Tests: 3 Total Pass: 2 Total Defects: 0 Total Failures: 1 Total Skips: 0 Total Todo: 0
    54. When Code Doesn’t Match Requirements
    55. A Bug Found <?PHP class DartsGame { protected $score; public function __construct() { $this->score = 501; } public function throwDart($score) { if ($this->score - $score < 0) { return $this->score; “3 throws results } in a score” $this->score = $this->score - $score; return $this->score; } public function getScore() { return $this->score; } }
    56. Solving the Bug • Keep track of “turns” and only score every 3 throws
    57. Dealing With the Bug <?PHP class DartsGame { protected $score; protected $throws; public function __construct() { $this->score = 501; $this->throws = array(); } public function throwDart($score) { Address the Bug $this->throws[] = $score; if (count($this->throws) < 3) { return $this->score; } $score = $this->throws[0] + $this->throws[1] + $this->throws[2]; $this->throws = array(); // ... }
    58. Fixed! jakobo@Hikaru ~/Dropbox/2009-06-18 unittesting/resources> snaptest.sh ./ ... ______________________________________________________________________ Total Cases: 3 Total Tests: 3 Total Pass: 3 Total Defects: 0 Total Failures: 0 Total Skips: 0 Total Todo: 0
    59. “What If” Thinking (Rules say: I was supposed to throw in 3’s) If I don’t throwDart() in a multiple of 3, what happens?
    60. “What If” Thinking • “Well then, I’d expect it to throw an exception” • Update the requirements, then add a test
    61. “TDD” or “Test First” <?PHP require_once 'basedarts_throws.php'; class Throw_Non_Multiple_Of_Three_Test extends Snap_UnitTestCase { public function setUp() { $this->Darts = new DartsGame(); $this->Darts->throwDart(50); $this->Darts->throwDart(50); } public function tearDown() { unset($this->Darts); } “I expect _____ to happen” public function testGetScoreThrowsException() { $this->willThrow("Exception"); $this->Darts->getScore(); $this->assertFalse(true, 'An exception was not thrown'); } }
    62. Of Course it Fails jakobo@Hikaru ~/Dropbox/2009-06-18 unittesting/resources> snaptest.sh ./ ...F FALSE assertion got TRUE. [bool(true) !== bool(false)] with user message: An exception was not thrown in method: testGetScoreThrowsException in class: Throw_Non_Multiple_Of_Three_Test in file: /Users/jakobo/Dropbox/2009-06-18 unittesting/resources/ basedarts_multiple.stest.php ______________________________________________________________________ Total Cases: 4 Total Tests: 4 Total Pass: 3 Total Defects: 0 Total Failures: 1 Total Skips: 0 Total Todo: 0 We should write that part...
    63. Write in Solution <?PHP class DartsGame { // ... public function getScore() { if (count($this->throws)) { throw new Exception('Darts must be thrown in multiples of 3'); } return $this->score; } } Meeting our requirement
    64. Our Results jakobo@Hikaru ~/Dropbox/2009-06-18 unittesting/resources> snaptest.sh ./ .... ______________________________________________________________________ Total Cases: 4 Total Tests: 4 Total Pass: 4 Total Defects: 0 Total Failures: 0 Total Skips: 0 Total Todo: 0
    65. You Just Learned “TDD”
    66. Refactoring • Change the internals freely • “throws” array • way score is tallied • Verify your “rules” are still adhered to
    67. Refactoring <?PHP class DartsGame { // ... public function throwDart($score) { $this->throws[] = $score; if (count($this->throws) < 3) { return $this->score; } $throws = $this->throws; $this->throws = array(); return $this->scoreTrio($throws[0], $throws[1], $throws[2]); } // ... protected function scoreTrio($throw_one, $throw_two, $throw_three) { $score = $throw_one + $throw_two + $throw_three; if ($this->score - $score < 0) { return $this->score;
    68. Refactoring // ... protected function scoreTrio($throw_one, $throw_two, $throw_three) { $score = $throw_one + $throw_two + $throw_three; if ($this->score - $score < 0) { return $this->score; } $this->score = $this->score - $score; return $this->score; } }
    69. And Rerun Tests jakobo@Hikaru ~/Dropbox/2009-06-18 unittesting/resources> snaptest.sh ./ .... ______________________________________________________________________ Total Cases: 4 Total Tests: 4 Total Pass: 4 Total Defects: 0 Total Failures: 0 Total Skips: 0 Total Todo: 0
    70. Advocacy / Recap • Testing is a good thing • Testing is easy • We’re testing requirements, not code
    71. Advocacy / Recap • There are frameworks for testing • Tests can be automated
    72. Advocacy / Recap • You can test new and established code • You can refactor code safely
    73. Next Steps • Download a framework • Check your requirements • Write some tests • Be happier!
    74. Unit Testing First Steps Jakob Heuser http://www.slideshare.net/jakobo
    75. Appendix http://www.flickr.com/photos/ratterrell/125200561 http://www.flickr.com/photos/wili/214316968 http://www.flickr.com/photos/mommamia/210433527 http://www.flickr.com/photos/syldavia/206163304 http://www.flickr.com/photos/mr_o/3606222762/
    76. Appendix http://www.flickr.com/photos/frield/95509221/ http://flickr.com/photos/deerwooduk/579761138 http://www.flickr.com/photos/brom/1329688851

    + Jakob HeuserJakob Heuser, 4 months ago

    custom

    494 views, 1 favs, 0 embeds more stats

    More info about this document

    CC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike License

    Go to text version

    • Total Views 494
      • 494 on SlideShare
      • 0 from embeds
    • Comments 0
    • Favorites 1
    • Downloads 9
    Most viewed embeds

    more

    All embeds

    less

    Flagged as inappropriate Flag as inappropriate
    Flag as inappropriate

    Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

    Cancel
    File a copyright complaint
    Having problems? Go to our helpdesk?

    Categories