Slide 1

Slide 1 text

@jcarouth / #ssphp also known as testing from the pit of despair Introducing Tests in Legacy PHP Applications

Slide 2

Slide 2 text

Howdy! I am Jeff Carouth I have written many, many lines of legacy code. @jcarouth I work at Liftopia employing the techniques I am going to present today.

Slide 3

Slide 3 text

What He Said

Slide 4

Slide 4 text

Legacy Code?

Slide 5

Slide 5 text

Legacy Code IS difficult to change often unstructured and likely incomprehensible “Test resistant”

Slide 6

Slide 6 text

$body->compile_dir = $body->template_dir."/compiled"; //determine the controller that should be used for this request based on which // controller name is passed through the query string. If there is not a // controller name in the query string, we will assume that the request is for // the index page if ( true == isset( $_GET['controller'] ) && true == is_string( $_GET['controller']) && $_GET['c $page = trim( $_GET['controller'] ); unset( $_GET['controller'] ); } else { $page = ""; } // If we have a separate intro page defined, it should be rendered. if( SEPARATE_INTRO !== false && $page === "" ) { if( true == is_file( "controllers/" . SEPARATE_INTRO . ".php" ) ) { include_once "controllers/" . SEPARATE_INTRO . ".php"; } $body->display( SEPARATE_INTRO . ".html" ); } else { $content = new Smarty(); $content->template_dir = "html"; $content->compile_dir = $body->template_dir."/compiled"; if( $page === "" ) { $page = DEFAULT_PAGE; } // Determine what, if any, view should be presented to the client. If there is

Slide 7

Slide 7 text

Should Vs. Must

Slide 8

Slide 8 text

RESIST the urge to Rewrite

Slide 9

Slide 9 text

REFACTOR only what is necessary for tests

Slide 10

Slide 10 text

Legacy Code Change Algorithm 1. Identify change points. 2. Find test points. 3. Break dependencies. 4. Write tests. 5. Make changes and refactor. Source: Working Effectively with Legacy Code by Michael Feathers

Slide 11

Slide 11 text

Break Dependencies Without Tests In Place? Migraine.

Slide 12

Slide 12 text

Mechanism For Feedback

Slide 13

Slide 13 text

Acceptance Tests masquerade as pinning tests

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

Test Introduction Algorithm 1. Identify what you need to change. 2. Write pinning test for impacted behavior. 3. Locate test point for unit test. 4. Break dependencies. 5. Write tests. 6. Make changes and refactor. 7. Repeat 5 and 6 until change is completed.

Slide 16

Slide 16 text

The FizzBuzzer Because, really, people will fund anything

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

Anonymous users can run FizzBuzz but only up to to the number 100

Slide 19

Slide 19 text

Whether the job is big or small, do it right or not at all

Slide 20

Slide 20 text

Identify Change Points

Slide 21

Slide 21 text

FizzBuzz!

Result

Slide 22

Slide 22 text

Write Pinning Tests

Slide 23

Slide 23 text

Feature: Anonymous Run FizzBuzz As a non-registered fizzbuzz enthusiast I need to be able to run fizzbuzz on a range of numbers So that I can get my fix of fizzbuzziness Scenario: Anonymous users should be able to run the fizzbuzzer When I am on homepage And I run fizzbuzz on range "12" to "20" Then I should see "Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz" Scenario: Anonymous users should be able to run a second fizzbuzz When I am on homepage And I run fizzbuzz on range "3" to "5" Then I should see "Fizz 4 Buzz" When I run fizzbuzz on range "9" to "12" Then I should see "Fizz Buzz 11 Fizz"

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

Refactor and Make Changes

Slide 26

Slide 26 text

Then I should see "Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz" Scenario: Anonymous users should be able to run a second fizzbuzz When I am on homepage And I run fizzbuzz on range "3" to "5" Then I should see "Fizz 4 Buzz" When I run fizzbuzz on range "9" to "12" Then I should see "Fizz Buzz 11 Fizz" Scenario: Anonymous users should not be able to exceed 100 When I am on homepage And I run fizzbuzz on range "95" to "101" Then I should see "101 is beyond the maximum value, 100" And I should see "Buzz Fizz 97 98 Fizz Buzz"

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

class FizzBuzzTest extends \PHPUnit_Framework_TestCase { /** * @test */ public function normalizeRangeForAnonShouldTruncateAt100() { $normalizedRange = fizzbuzz_normalize_range(95, 101, false); $this->assertTrue($normalizedRange['can_process']); $this->assertEquals(100, $normalizedRange['end']); } /** * @test */ public function signedInUsersCanUseIntegersOver100() { $range = fizzbuzz_normalize_range(95, 101, true); $this->assertTrue($range['can_process']); $this->assertEquals(101, $range['end']); } }

Slide 29

Slide 29 text

function fizzbuzz_normalize_range($start, $end, $is_user = false) { $can_process = true; $message = ''; if (!$is_user) { //anon can only fizzbuzz for ranges up to 100 if ($end > 100) { $message = '$end.'is 'beyond the maximum value, 100” $end = 100; } } return array( 'can_process' => $can_process, 'message' => $message, 'start' => $start, 'end' => $end, ); }

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

Freedom to Refactor FEARLESSLY

Slide 34

Slide 34 text

Create Abstractions expose the API you want, guided by tests

Slide 35

Slide 35 text

Thank You! Questions? http://speakerdeck.com/jcarouth @jcarouth | [email protected] https://joind.in/8025