Slide 1

Slide 1 text

Unit Testing

Slide 2

Slide 2 text

What is unit testing?

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

Why Test Code? 6Reasons

Slide 7

Slide 7 text

1 Prove that code actually works

Slide 8

Slide 8 text

1 Prove that code actually works 2 Improve the design without breaking it

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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:

Slide 18

Slide 18 text

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:

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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); }

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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.

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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.

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

Plan Tests force you to think about what code should do, what values are being returned and how to get to there.

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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.

Slide 30

Slide 30 text

methodology Test Driven Development Behavior Driven Development Domain Driven Development

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

Behavior Driven Development - BDD is an agile method of testing. - Tests uses real world examples. - It - Should - Given - Keywords:

Slide 33

Slide 33 text

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.

Slide 34

Slide 34 text

theory Set up conditions for testing Call the method being tested Verify the results Clean up

Slide 35

Slide 35 text

theory Tests should be independent Give tests clear, verbose names Don’t run unneeded assertions

Slide 36

Slide 36 text

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/)

Slide 37

Slide 37 text

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/)

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

Installing PHPUnit PEAR (http://mlo.io/blog/2012/02/02/perfect- dev-setup-lion.html) pear config-set auto_discover 1 pear install pear.phpunit.de/PHPUnit

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

PHPUnit 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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

PHPUnit More documentation at http://www.phpunit.de/manual/current/en/ index.html

Slide 45

Slide 45 text

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/)

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

FUnit

Slide 48

Slide 48 text

FUnit -Tests are run with fu::run method -Call file with php command

Slide 49

Slide 49 text

FUnit More documentation at http://git.io/funit

Slide 50

Slide 50 text

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/)

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

Sane Programmers Test Their Code