unit testing in php

Post on 11-Nov-2014

3.086 Views

Category:

Technology

4 Downloads

Preview:

Click to see full reader

DESCRIPTION

Talk given at Silicon Valley LAMP Meetup Aug 28, 2008

TRANSCRIPT

Unit Testing in PHP

Rudolph Jakob Heuserjakob@felocity.org

http://www.slideshare.net/jakobo

Who Is This Guy?

Sr. Software Engineer

PHP, JS, CSS

Python for kicks

Hates “echo” debugging

A Unit Test

public function testActionTakenIsInJob() { return $this->assertRegex($this->job->post, '/action_taken='.self::ACTION_TAKEN.'/'); } public function testTypeIsGeneratorInJob() { return $this->assertRegex($this->job->post, '/type=generator/'); } public function testGeneratorIsNamedInJob() { return $this->assertRegex($this->job->post, '/generator='.self::ACTION_TAKEN.'/'); } public function testActingUserIdIsNamedInJob() { return $this->assertRegex($this->job->post, '/acting_user_id='.self::ACTING_USER.'/'); } public function testURLIsInJob() { return $this->assertEqual($this->job->url, DataFeed::JOB_URL); } public function testStartTimeIsInJob() { return $this->assertEqual($this->job->start, self::TIME_NOW); }

A Unit Test Simplified

• A set of rules

• Predictable Dependancies

• Input / Output

A contract between adeveloper and their code

Ready to Use

SnapTest

PHPUnit

Testilence

SimpleTest

Why Test?

<?php

//...echo 'a';var_dump($file);var_dump($result);// ...echo 'b';var_dump($result);// ...echo 'c';

<?php

class Rube_Goldberg { // ... protected function iDontEvenKnowWhatThisDoesYet() { // ... } public function iAddedThisInterfaceItemJustInCase() { // ... }}

• Helps us debug

• Helps us refactor safely

• Keeps us from over engineering

• Long term saves time and money

Before

During

After

Always Test

What to Test?

Unit: the smallest testable part of an application

File Include Function Class Method

Ignore the Obvious

<?php

class Foo { protected $bar; public function setBar($baz) { $this->bar = $baz; }}

How do we Test?

An Example:The Game of Darts

Simple Darts Rules

• Start at 501 Points

• Goal is to get to 0

• 3 throws results in a score

• Must finish on 0 exactly

The “TDD” Concept

1. Decide the next “How Should it Work”

2. Write the Test

3. Verify the Failure

4. Write the Code

5. Verify the Success

The “TDD” Concept

• A Dart Game should start at 501 points

• If I ask a new dart game its score, it should tell me 501

• new DartGame() (constructor) and getScore() are required

<?php

class DartGame_Test extends Snap_UnitTestCase { public function setUp() {} public function tearDown() {} public function testGameStartsAt501() { $game = new DartGame(); return $this->assertEqual($game->getScore(), 501); }}

jakobo ~/Desktop/testing> ~/development/snaptest/snaptest.sh ./F/Users/jakobo/Desktop/testing/code/tests/base.stest.php had a fatal error: Fatal error: Class 'DartGame' not found in /Users/jakobo/Desktop/testing/code/tests/base.stest.php on line 8

______________________________________________________________________Total Cases: 0Total Tests: 1Total Pass: 0Total Defects: 0Total Failures: 1Total Skips: 0Total Todo: 0jakobo ~/Desktop/testing>

<?php

class DartGame { public function getScore() { return 501; }}

jakobo ~/Desktop/testing> ~/development/snaptest/snaptest.sh ./.______________________________________________________________________Total Cases: 1Total Tests: 1Total Pass: 1Total Defects: 0Total Failures: 0Total Skips: 0Total Todo: 0jakobo ~/Desktop/testing>

Back to Design

• A turn is 3 throws

• Two di!erent ways to score a turn

score() Interface

1. $game->score($one, $two, $three)

2. $game->score($one);$game->score($two);$game->score($three);

<?php

require dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'dartgame.class.php';

class DartGame_Test extends Snap_UnitTestCase { public function setUp() {} public function tearDown() {} public function testGameStartsAt501() { $game = new DartGame(); return $this->assertEqual($game->getScore(), 501); } public function testScore10and10and10CreatesScoreOf471() { $game = new DartGame(); $game->score(10, 10, 10); return $this->assertEqual($game->getScore(), 471); }}

jakobo ~/Desktop/testing> ~/development/snaptest/snaptest.sh ./.F/Users/jakobo/Desktop/testing/code/tests/base.stest.php had a fatal error: Fatal error: Call to undefined method DartGame::score() in /Users/jakobo/Desktop/testing/code/tests/base.stest.php on line 16

______________________________________________________________________Total Cases: 1Total Tests: 2Total Pass: 1Total Defects: 0Total Failures: 1Total Skips: 0Total Todo: 0jakobo ~/Desktop/testing>

<?php

class DartGame { public function getScore() { return 501; } public function score($one, $two, $three) {}}

jakobo ~/Desktop/testing> ~/development/snaptest/snaptest.sh ./F.Equal (==) assertion failed. [int(471) != int(501)] in method: testScore10and10and10CreatesScoreOf471 in class: DartGame_Test in file: /Users/jakobo/Desktop/testing/code/tests/base.stest.php______________________________________________________________________Total Cases: 1Total Tests: 2Total Pass: 1Total Defects: 0Total Failures: 1Total Skips: 0Total Todo: 0jakobo ~/Desktop/testing>

<?php

class DartGame { protected $score; public function __construct() { $this->score = 501; } public function getScore() { return $this->score; } public function score($one, $two, $three) { $this->score = $this->score - $one - $two - $three; }}

jakobo ~/Desktop/testing> ~/development/snaptest/snaptest.sh ./..______________________________________________________________________Total Cases: 1Total Tests: 2Total Pass: 2Total Defects: 0Total Failures: 0Total Skips: 0Total Todo: 0jakobo ~/Desktop/testing>

Ending Exactly On 0

If score goes below 0, don’t count

<?php

require dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'dartgame.class.php';

class DartGame_Test extends Snap_UnitTestCase { public function setUp() {} public function tearDown() {} public function testGameStartsAt501() { $game = new DartGame(); return $this->assertEqual($game->getScore(), 501); } public function testScore10and10and10CreatesScoreOf471() { $game = new DartGame(); $game->score(10, 10, 10); return $this->assertEqual($game->getScore(), 471); } public function testScoreGoingBelowZeroLeavesScoreAboveZero() { $game = new DartGame(); $game->score(60, 60, 60); $game->score(60, 60, 60); $game->score(60, 60, 60); // should not be applied return $this->assertEqual($game->getScore(), 141); }}

jakobo ~/Desktop/testing> ~/development/snaptest/snaptest.sh ./F..Equal (==) assertion failed. [int(141) != int(-39)] in method: testScoreGoingBelowZeroLeavesScoreAboveZero in class: DartGame_Test in file: /Users/jakobo/Desktop/testing/code/tests/base.stest.php______________________________________________________________________Total Cases: 1Total Tests: 3Total Pass: 2Total Defects: 0Total Failures: 1Total Skips: 0Total Todo: 0jakobo ~/Desktop/testing>

<?php

class DartGame { protected $score; public function __construct() { $this->score = 501; } public function getScore() { return $this->score; } public function score($one, $two, $three) { $score = $this->score - $one - $two - $three; if ($score >= 0) { $this->score = $score; } }}

jakobo ~/Desktop/testing> ~/development/snaptest/snaptest.sh ./...______________________________________________________________________Total Cases: 1Total Tests: 3Total Pass: 3Total Defects: 0Total Failures: 0Total Skips: 0Total Todo: 0jakobo ~/Desktop/testing>

And Then We...

• Validation for score(), bounding

• Obscure rules (checking out)

• Same process again

More Cool Stuff

• Mock Objects: “Fake” objects for dependancies

• Asserting Call Counts

• Expectations (For Call Counts and Mocks)

Get Testing

SnapTesthttp://www.snaptest.net

PHPUnithttp://www.phpunit.de

Testilencehttp://www.testilence.org

SimpleTesthttp://www.simpletest.org

Unit Testing in PHP

Rudolph Jakob Heuserjakob@felocity.org

http://www.slideshare.net/jakobo

LicenseThis presentation is presented under the Creative Commons Attribution Share-Alike License

You are free:

to share, copy, distribute, or transmit this work

to remix and adapt this work

Under the following conditions:

Attribution: You must attribute the work that uses material under this license to the original licensor (but not in a way that suggests or implies they endorse you or your use of the work)

Share Alike: If you alter, transform, or build upon the work, you may distribute the resulting work only under the same, similar, or compatible license.

Any of the above conditions can be waived with permission from the copyright holder.

http://creativecommons.org/licenses/by-sa/3.0/us/

top related