Download pdf - Unittests für Dummies

Transcript
Page 1: Unittests für Dummies

Unit Testing für Dummies

15.11.2009

Lars Jankowfsky, swoodoo AGThorsten Rinne, Mayflower GmbH

Page 2: Unittests für Dummies

About me:

PHP, C++, Developer, Software Architect since 1992

PHP since 1998

Many successful projects from 2 to 20 developers

Running right now three projects using eXtreme Programming

CTO and (Co-)Founder swoodoo AG

(Co-)Founder OXID eSales AG

Page 3: Unittests für Dummies

About me:

Diplom-Informatiker (FH) Certified Scrum MasterZend Certified Engineer

PHP since 1999

Many successful projects from 2 to 6 developers using Scrum, eXtreme Programming, Crystal Clear

Senior Developer / Team Lead at Mayflower GmbH

Master of phpMyFAQ

Page 4: Unittests für Dummies

(c) aboutpixel.de(c) spackletoe http://www.flickr.com/photos/spackletoe/90811910/)

Page 5: Unittests für Dummies

Unit Tests?

PHPUnit Fixtures

Stubs Pitfalls

Page 7: Unittests für Dummies

PHPUnit

phpunit myTest

user@workshop:/var/www/thorsten-zfguestbook/tests/application$ phpunit controllers_PostsControllerTest

PHPUnit

Page 8: Unittests für Dummies

Fixtures

Page 9: Unittests für Dummies

Fixtures Fixtures

Make sure that tests don‘t alter fixture

Fixture is FIXture

if you feel creating fixtures is too much work - refactor more!

Do never let tests leave altered tests

Page 11: Unittests für Dummies

YAML loading

public static function create($fileName) { $fileName = 'Fixtures'.DIRECTORY_SEPARATOR.$fileName; ob_start(); include $fileName; $fileContents = ob_get_contents(); ob_clean(); $yamlData = syck_load($fileContents); return $yamlData; }

Fixtures

Page 12: Unittests für Dummies

YAML storing

public static function load($fixtures, $tableName) { if (is_array($fixtures) && count($fixtures)) { foreach ($fixtures as $fixture) { if (is_array($fixture) && is_array(current($fixture))) { Fixtures::load($fixture, $tableName); } $fields = array_keys($fixture); $statement = "INSERT INTO $tableName (" . implode(', ', $fields) . ") VALUES (:" . implode(", :", $fields) . ")"; $stmt = self::$_db->prepare($statement); if (count($fixture)) { foreach ($fixture as $key => $value ) { $stmt->bindValue(':'.$key, $value); } } $stmt->execute(); self::$_usedTables[$tableName] = $tableName; } } }

Fixtures

Page 13: Unittests für Dummies

YAML - cleanup

if (!empty(self::$_usedTables)) { foreach (array_reverse(self::$_usedTables) as $tableName) { self::$_db->execute("TRUNCATE TABLE $tableName"); } }

Fixtures

Page 14: Unittests für Dummies

Fixtures the other side ...

manual fixtures are too much work

use a test database

think about automatic creation of YAML files

Fixtures

Page 15: Unittests für Dummies

Stubs

Page 16: Unittests für Dummies

Mocking stubs? Stubs

Unittesting is about testing a unit of work, not a complete workflow

isolates your code from external dependencies

can be done with PHPUnit, but you don‘t need to

Page 17: Unittests für Dummies

Mocking stubs The PHPUnit way Stubs

/** * A simple stub providing a simple result directly instead of using the database */class UserModelStub extends UserModel { public getUserCount() { return 10; }}

UserModelStub extends PHPUnit_Framework_Testcase { public function testGetUserCount() { $stub = $this->getMock(‘UserModel‘); $stub->expects($this->any())->method(‘getUserCount‘)->will($this->returnValue(10)); }}

Page 18: Unittests für Dummies

Pitfalls

Page 19: Unittests für Dummies

Code the unit test first. Pitfalls

OOP, public, private

Globals

Superglobals

Sessions

Cookies

Page 20: Unittests für Dummies

Dependencies ...

Separate logic from view

create accessors, add all parameters in calls

Pitfalls

Page 21: Unittests für Dummies

Dependency Example

class displayUserDetails(){ /** * Processes input and sends user first name, last name to display; */ function show() { global $dbLink; global $templateEngine; $itemId = (int) $_REQUEST['user_id']; $firstName = $dbLink->getOne("select first_name from users where id = $itemId"); $lastName = $dbLink->getOne("select last_name from users where id = $itemId"); $templateEngine->addTemplateVar('firstName', $firstName); $templateEngine->addTemplateVar('lastName', $lastName); $templateEngine->display(); }}

Pitfalls

Page 22: Unittests für Dummies

Dependency Example

/** * A view class responsible for displaying user details. */class userView(){ /** * Loads user object and sends first name, last name to display */ public function show() { $userId = $this->_inputProcessor->getParameter("user_id"); $this->templateEngine->addTemplateVar('user', $this->model->loadUser(userId)); $this->templateEngine->display(); }} /** * And the corresponding model */class userModel(){ public function loadUser($userId) { $user = new User( $userId ); return array('firstName' => $user->getFirstName(), 'lastName' => $user->getLastName()); }}

Pitfalls

Page 23: Unittests für Dummies

STOP

Page 24: Unittests für Dummies
Page 25: Unittests für Dummies

class someOtherClass { var $setting;

function calculateSomething($a, $b) { return $a+$b; }}

class myOldNastyClass {

function needToTestThisFunction() {

$class = new someOtherClass();

$z = $_GET['input'];

// ....

return $class->calculateSomething( $class->setting, $z); }}

Layer Example Pitfalls

Page 26: Unittests für Dummies

Layer Example

class someOtherClass { private $setting;

public function calculateSomething($a, $b) { return $a+$b; }

public function setSetting($set) { $this->setting = $set; }

public function getSetting() { return $this->setting; }}

class myInput { public function getParameter($name) { return $_GET[$name]; }}

class myOldNastyClass {

private $input; // set e.g. in constructor

public function needToTestThisFunction(someOtherClass &$class, $z) {

$z = $input->getParameter('input'); // ....

return $class->calculateSomething( $class->getSetting(), $z); }}

Pitfalls

Page 27: Unittests für Dummies

(c) istockphoto

Page 28: Unittests für Dummies

„Questions?“


Recommended