Dr Strange Result.ppt

Views:
 
Category: Education
     
 

Presentation Description

No description available.

Comments

Presentation Transcript

Dr. StrangeResult(Or: how I Learned To Stop Worrying And Love Unit Testing) : 

Dr. StrangeResult(Or: how I Learned To Stop Worrying And Love Unit Testing) George Schlossnagle<[email protected]> April 25, 2003 PHP-Con

What Is Unit Testing : 

What Is Unit Testing Unit Testing != XP A systematic way of testing small portions (‘units’) of code A way to avoid accidentally breaking working code.

Why Unit Test : 

Why Unit Test Reducing time debugging means more time for productive development. Interdependencies grow as codebase grows

Common Excuses For Not Unit Testing : 

Common Excuses For Not Unit Testing The project is too rushed My code always works the first time It works on my machine

Features Needed For Effective Unit Testing Suite : 

Features Needed For Effective Unit Testing Suite Automated Easy To Write Extensible Comprehensive Reusable

An Intro To PHPUnit : 

An Intro To PHPUnit Install Howto > pear install PHPUnit

Our First Unit Test (I) : 

Our First Unit Test (I) class EmailAddress { var $localPart; var $domain; var $address; function EmailAddress($address = null) { If($address) { $this->address = $address; $this->extract(); } } function extract() { list($this->localPart, $this->domain) = explode("@", $this->address); } }

Our First Unit Test (II) : 

Our First Unit Test (II) class EmailAddressTest extends PHPUnit_TestCase{ function EmailAddressTest($name) { PHPUnit_TestCase::PHPUnit_TestCase($name); } function testLocalPart() { $email = new EmailAddress("[email protected]"); // check that the local part of the address // is equal to 'george' $this->assertTrue($email->localPart == 'george'); } function testDomain() { $email = new EmailAddress("[email protected]"); $this->assertTrue($email->domain == ’omniti.com'); } }

Our First Unit Test (III)running the tests : 

Our First Unit Test (III)running the tests <?php $suite = new PHPUnit_TestSuite(); $suite->addTest(new EmailAddressTestCase(‘testLocalPart’)); $suite->addTest(new EmailAddressTestCase(‘testDomain’)); $result = PHPUnit::run($suite); echo $result->toString(); ?> > php EmailAddress.phpt TestCase emailaddresstestcase->testlocalpart() passed TestCase emailaddresstestcase->testdomain() passed

Our First Unit Test (III)autoregistering a testcase class : 

Our First Unit Test (III)autoregistering a testcase class <?php $suite = new PHPUnit_TestSuite(‘EmailAddressTestCase’); $result = PHPUnit::run($suite); echo $result->toString(); ?> > php EmailAddress.phpt TestCase emailaddresstestcase->testlocalpart() passed TestCase emailaddresstestcase->testdomain() passed

A Cute Trick : 

A Cute Trick Add an ‘execute only as parent’ block to allow your test cases to seamlessly work as standalone scripts and included libraries. <?php if($_SERVER[‘PHP_SELF’] == __FILE__) { $suite = new PHPUnit_TestSuite(‘EmailAddressTestCase’); $result = PHPUnit::run($suite); echo $result->toString(); } ?>

Performing Setup : 

Performing Setup class EmailAddressTestCase extends PHPUnit_TestCase{ var $email; var $localPart; var $domain; function EmailAddressTestCase($name) { PHPUnit_TestCase::PHPUnit_TestCase($name); } function setUp() { $this->email = new EmailAddress("[email protected]"); $this->localPart = 'georg'; $this->domain = 'omniti.com'; } function testLocalPart() { $email =& $this->email; $this->assertEquals($email->localPart, $this->localPart) } function testDomain() { $email =& $this->email; $this->assertEquals($email->domain, $this->domain); } }

Informative Error Messages : 

Informative Error Messages TestCase emailaddresstestcase->testlocalpart() failed: expected george, actual georg This message is rather cryptic. Instead we can configure our test cases tor return more verbose messages. function testLocalPart() { $email =& $this->email; $this->assertEquals($email->localPart, $this->localPart, "localParts: $email->localPart of $email->address != $this->localPart"); } > php-4.3.2 EmailAddress.phpt TestCase emailaddresstestcase->testdomain() passed TestCase emailaddresstestcase->testlocalpart() failed: localParts: george of [email protected] != georg

Implementing Listeners : 

Implementing Listeners class EmailAddressListener extends PHPUnit_TestListener { function addError(&$test, &$t) { print "Error in ".$test->getName()."\n"; print "Error message: $t\n"; } function addFailure(&$test, &$t) { print "Failure in ".$test->getName()."\n"; print "Error message: $t\n"; } function startTest(&$test) { print "Begining of test ".$test->getName()."\n"; } function endTest(&$test) { print "End of test ".$test->getName()."\n"; } }

Implementing Listeners (II) : 

Implementing Listeners (II) To attach our listener to our result set and run it we do: $suite = new PHPUnit_TestSuite('EmailAddressTestCase'); $result = new PHPUnit_TestResult; $result->addListener(new EmailAddressListener); $suite->run($result); echo $result->toString();

Implementing Listeners (III) : 

Implementing Listeners (III) A smarter Listener class EmailAddressListener extends PHPUnit_TestListener { var $owner = ‘[email protected]’; var $message = ‘’; function addError(&$test, &$t) { $this->message = "Error in ".$test->getName().”\n$t\n"; } function addFailure(&$test, &$t) { $this->message = "Failure in ".$test->getName().”\n$t\n”; } function startTest(&$test) { print "Begining of test ".$test->getName()."\n"; } function endTest(&$test) { if($this->message) { $date = strftime("%D %H:%M:%S"); mail($this->owner, “Test Failed at $date”, $this->message); } } }

Packaging Many Tests Together : 

Packaging Many Tests Together class PHPUnit_TestHarness { var $suite; function PHPUnit_TestHarness() { $this->suite = new PHPUnit_TestSuite(); } function register($file) { require_once($file); } function run() { foreach( get_declared_classes() as $class) { if(substr($class, -8, 8) == 'testcase') { $this->suite->addTestSuite($class); } } return PHPUnit::run($this->suite); } }

Using Unit Tests AsPart of Test Driven Design : 

Using Unit Tests AsPart of Test Driven Design Never write code without it addressing a test which fails. Tests written to ensure satisfaction of requirements. No code is committed unless all tests are successful. Code is simply made to work, Optimization happens later.

Tests For Text_Statistics : 

Tests For Text_Statistics class Text_WordTestCase extends PHPUnit_TestCase { var $known_words; function Text_WordTestCase($name) { $this->PHPUnit_TestCase($name); } function setup() { $this->known_words = array ( 'the' => 1, 'late' => 1, 'hello' => 2, 'frantic' => 2, 'programmer' => 3); } function testKnownWords() { foreach ($this->known_words as $word => $syllables) { $obj = new Text_Word($word); $this->assertEquals( $syllables, $obj->numSyllables(), "$word has incorrect syllable count” ); } } }

Using Unit Tests In Existing Code Bases : 

Using Unit Tests In Existing Code Bases Good for preparing to reimplement sections of your code base. Write tests for libraries to be changed. Start small. Be thorough.

Testing Database Backed Application : 

Testing Database Backed Application Absolutely need a testing environment. For testing complete data replication is not necessary (as opposed to benchmarking) Using a database wrapper library can allow you to easily switch between production and test databases.

Testing Web Applications : 

Testing Web Applications In a well architected system, no non-display logic occurs ‘inside’ pages, only in libraries. cURL is your friend.

Shameless Book Plug : 

Shameless Book Plug Available Aug 2003 From Sams Publishing

authorStream Live Help