Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Unit Testing

Unit Testing

A talk I gave about Unit Testing. I only go into two unit testing frameworks.

Matthew Loberg

July 18, 2012
Tweet

More Decks by Matthew Loberg

Other Decks in Programming

Transcript

  1. unit tests determine if small units of source code are

    fit for use What is unit testing?
  2. unit tests determine if small units of source code are

    fit for use What is unit testing?
  3. unit tests determine if small units of source code are

    fit for use What is unit testing?
  4. 1 Prove that code actually works 2 Improve the design

    without breaking it 3Detect regressions
  5. 1 Prove that code actually works 2 Improve the design

    without breaking it 3Detect regressions 4 Provides sample code
  6. 1 Prove that code actually works 2 Improve the design

    without breaking it 3Detect regressions 4 Provides sample code 5 Forces you to plan before you code
  7. 1 Prove that code actually works 2 Improve the design

    without breaking it 3Detect regressions 4 Provides sample code 5 Forces you to plan before you code 6 Reduces bugs
  8. 1 Prove that code actually works 2 Improve the design

    without breaking it 3Detect regressions 4 Provides sample code 5 Forces you to plan before you code 6 Reduces bugs
  9. Prove Code Works function add($a, $b) { $x = $a

    + $b; return $x; } How do we know this works?
  10. Prove Code Works function some_complex_formula($a, $b) { $x = ($a

    * 2.3747); $y = ($b ^ 3); return $y; $z = $y - $x; return $z; }
  11. Prove Code Works function some_complex_formula($a, $b) { $x = ($a

    * 2.3747); $y = ($b ^ 3); return $y; $z = $y - $x; return $z; }
  12. Prove Code Works function getLexileScore($ability_prior, $sigma_prior, $raw_score, $num_days, $item_difficulties, $item_difficulties_count)

    { if (is_array($item_difficulties)) { $item_difficulties = rawurlencode(implode(‘,’, $item_difficulties)); } if (is_array($item_difficulties_count)) { $item_difficulties_count = rawurlencode(implode(‘,’, $item_difficulties_count)); } $postdata = array( ‘ability_prior’ => $ability_prior, ‘sigma_prior’ => $sigma_prior, ... ); $postdata = http_build_query($postdata); $ch = curl_init(URL_LEXILE_SCORE.’/score_test.xml’); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata); ... } Real world example:
  13. Prove Code Works function getLexileScore($ability_prior, $sigma_prior, $raw_score, $num_days, $item_difficulties, $item_difficulties_count)

    { if (is_array($item_difficulties)) { $item_difficulties = rawurlencode(implode(‘,’, $item_difficulties)); } if (is_array($item_difficulties_count)) { $item_difficulties_count = rawurlencode(implode(‘,’, $item_difficulties_count)); } $postdata = array( ‘ability_prior’ => $ability_prior, ‘sigma_prior’ => $sigma_prior, ... ); $postdata = http_build_query($postdata); $ch = curl_init(URL_LEXILE_SCORE.’/score_test.xml’); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata); ... } $item_difficulties = rawurlencode(implode(‘,’, $item_difficulties)); $item_difficulties_count = rawurlencode(implode(‘,’, $item_difficulties_count)); $postdata = http_build_query($postdata); Real world example:
  14. 1 Prove that code actually works 2 Improve the design

    without breaking it 3Detect regressions 4 Provides sample code 5 Forces you to plan before you code 6 Reduces bugs
  15. Improve Design function hash_password($input, $cost = 10) { $salt =

    ‘$2a$’ . str_pad($cost, 2, ‘0’, STR_PAD_LEFT) . ‘$’; $salt .= substr(str_replace(‘+’, ‘.’, base64_encode(openssl_random_pseudo_bytes(16))), 0, 22); return crypt($input, $salt); }
  16. Improve Design function hash_password($input, $cost = 10) { return crypt($input,

    generate_salt($cost)); } function generate_salt($cost = 10) { if ($cost < 4 || $cost > 31) { throw new Exception(‘Cost must be between 4 and 31’); } $salt = ‘$2a$’ . str_pad($cost, 2, ‘0’, STR_PAD_LEFT) . ‘$’; $salt .= substr(str_replace(‘+’, ‘.’, base64_encode(openssl_random_pseudo_bytes(16))), 0, 22); return $salt; } Step 3 in Test Driven Development
  17. 1 Prove that code actually works 2 Improve the design

    without breaking it 3Detect regressions 4 Provides sample code 5 Forces you to plan before you code 6 Reduces bugs
  18. Detect Regressions -Regressions are things that used to work but

    no longer do. -When you make a change to code, how do you know if it will affect more then just code you are editing? -With tests, you can know for sure if everything is working as it was.
  19. 1 Prove that code actually works 2 Improve the design

    without breaking it 3Detect regressions 4 Provides sample code 5 Forces you to plan before you code 6 Reduces bugs
  20. Sample Code - Source code can be hard to read.

    - Docblocks are only so helpful. - Tests provide the code being used, no guessing how it works.
  21. 1 Prove that code actually works 2 Improve the design

    without breaking it 3Detect regressions 4 Provides sample code 5 Forces you to plan before you code 6 Reduces bugs
  22. Plan Tests force you to think about what code should

    do, what values are being returned and how to get to there.
  23. 1 Prove that code actually works 2 Improve the design

    without breaking it 3Detect regressions 4 Provides sample code 5 Forces you to plan before you code 6 Reduces bugs
  24. Reduces Bugs -Notice I didn’t say prevents. -Like it or

    not, bugs are a part of code, but validating code can reduce the number of bugs introduced.
  25. Test Driven Development - TDD or Test-First Development is a

    process where tests are written before any code is. - There are 3 steps in TDD. 1. Write tests that fail. 2. Write code to make them pass. 3. Refactor code. 4. Repeat
  26. Behavior Driven Development - BDD is an agile method of

    testing. - Tests uses real world examples. - It - Should - Given - Keywords:
  27. Domain Driven Development - DDD is business model of testing.

    - The core model of the business is the basis for all designs and tests. - Initiates a collaboration between the technical and business side of a project to get to the heart of the problem.
  28. Test Frameworks PHP JavaScript Ruby Shell PHPUnit FUnit (http://www.phpunit.de/) (http://git.io/funit)

    Jasmine (http://pivotal.github.com/jasmine/) Mocha (http://visionmedia.github.com/mocha/) Test::Unit (standard library) RSpec (http://rspec.info/) Cucumber (http://cukes.info/) shunit2 (http://code.google.com/p/shunit2/) roundup (http://bmizerany.github.com/roundup/)
  29. Test Frameworks PHP JavaScript Ruby Shell PHPUnit FUnit (http://www.phpunit.de/) (http://git.io/funit)

    Jasmine (http://pivotal.github.com/jasmine/) Mocha (http://visionmedia.github.com/mocha/) Test::Unit (standard library) RSpec (http://rspec.info/) Cucumber (http://cukes.info/) shunit2 (http://code.google.com/p/shunit2/) roundup (http://bmizerany.github.com/roundup/)
  30. PHPUnit -Most popular PHP testing framework -TDD with BDD/DDD support

    -Installed via PEAR -Ability to run tests against a database or mock a third-party service -Had to modify the autoloader method in myOn to get working
  31. PHPUnit -Class name is the class you are testing followed

    by Test (tests for Foo would be FooTest) * most of the time -Inherits from PHPUnit_Framework_TestCase* -Test cases are public methods starting with test -File name should match class name
  32. PHPUnit <?php class LexileTest extends PHPUnit_Framework_TestCase { public function testScore()

    { $score = Lexile::getLexileScore(500, 100, 3, 0, array(500, 600, 700), array(1, 1, 1)); $this->assertEquals(552, $score[‘score’]); $this->assertEquals(92, $score[‘sigma’]); $score = Lexile::getLexileScore(0, 0, 35, 10, 550, 35); $this->assertEquals(7, $score[‘score’]); $this->assertEquals(5, $score[‘sigma’]); } public function testForecast() { ... } } Example
  33. PHPUnit -Fixtures allow you to make sure the conditions for

    each test are the same protected function setUp() { ... } setUp - ran before each test protected function tearDown() { ... } tearDown - ran after each test protected static function setUpBeforeClass() { ... } setUpBeforeClass - static method called before any test protected static function tearDownAfterClass() { ... } tearDownAfterClass - static method called after all test
  34. PHPUnit -Tests are run with the ‘phpunit’ command -Last parameter

    is a single file or directory -Options * --bootstrap - File that is run before tests phpunit --bootstrap includes/app/config.php --verbose LexileTest phpunit --bootstrap includes/app/config.php --verbose tests
  35. Test Frameworks PHP JavaScript Ruby Shell PHPUnit FUnit (http://www.phpunit.de/) (http://git.io/funit)

    Jasmine (http://pivotal.github.com/jasmine/) Mocha (http://visionmedia.github.com/mocha/) Test::Unit (standard library) RSpec (http://rspec.info/) Cucumber (http://cukes.info/) shunit2 (http://code.google.com/p/shunit2/) roundup (http://bmizerany.github.com/roundup/)
  36. FUnit -Not to be confused with the Flex testing framework

    of the same name -Simple Unit tests for PHP 5.3+ -Single file -Colored output -Couldn’t find an easy way to test multiple files -Doesn’t provide exit status -No support for BDD or DDD -Easy installation git clone https://github.com/funkatron/FUnit.git
  37. FUnit <?php require(“includes/app/config.php”); use \FUnit\fu; require __DIR__ . ‘/FUnit.php’; fu::test(“Lexile

    Score”, function() { $score = Lexile::getLexileScore(500, 100, 3, 0, array(500, 600, 700), array(1, 1, 1)); fu::equal(552, $score[‘score’]); fu::equal(92, $score[‘sigma’]); $score = Lexile::getLexileScore(0, 0, 35, 10, 550, 35); fu::equal(7, $score[‘score’]); fu::equal(5, $score[‘sigma’]); }); Example
  38. FUnit -Tests are run with fu::run method -Call file with

    php command <?php require(“includes/app/config.php”); use \FUnit\fu; require __DIR__ . ‘/FUnit.php’; fu::test(“Lexile Score”, function() { $score = Lexile::getLexileScore(500, 100, 3, 0, array(500, 600, 700), array(1, 1, 1)); fu::equal(552, $score[‘score’]); fu::equal(92, $score[‘sigma’]); $score = Lexile::getLexileScore(0, 0, 35, 10, 550, 35); fu::equal(7, $score[‘score’]); fu::equal(5, $score[‘sigma’]); }); php LexileTest.php
  39. Test Frameworks PHP JavaScript Ruby Shell PHPUnit FUnit (http://www.phpunit.de/) (http://git.io/funit)

    Jasmine (http://pivotal.github.com/jasmine/) Mocha (http://visionmedia.github.com/mocha/) Test::Unit (standard library) RSpec (http://rspec.info/) Cucumber (http://cukes.info/) shunit2 (http://code.google.com/p/shunit2/) roundup (http://bmizerany.github.com/roundup/)
  40. Funsies -Tests must pass before committing -Will not work with

    FUnit (as it doesn’t give a useful exit status) #!/bin/sh phpunit --bootstrap includes/app/config.php tests exit $? .git/hooks/pre-commit