Your SlideShare is downloading. ×
Unit testing
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Saving this for later?

Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime - even offline.

Text the download link to your phone

Standard text messaging rates apply

Unit testing

493
views

Published on

unit testing in PHP with PHPUnit

unit testing in PHP with PHPUnit

Published in: Education, Technology

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
493
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
5
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide
  • But what if we could use it?! (Eureka! Archimedes reference)
  • Transcript

    • 1. Unit Testing By David Haskins
    • 2. bool underAttack = false; underAttack = detectEvents(); //do some other stuff if(underAttack = true) { launchNuclearMissles(); } else { alert(“false alarm!”); }
    • 3. Why Test? • Sometimes we make mistakes in our code
    • 4. Why Test? • Sometimes we make mistakes in our code • Sometimes we forget to finish parts of our code because we get interrupted, and then we never come back and finish
    • 5. Why Test? • Sometimes we make mistakes in our code • Sometimes we forget to finish parts of our code because we get interrupted, and then we never come back and finish • //TODO: add another reason
    • 6. Testing vs. Debugging Testing: detecting errors Debugging: diagnose and repair detected errors
    • 7. Types of testing regression tests functional tests acceptance tests integration tests load/stress tests security tests unit tests
    • 8. Unit Testing Unit Testing: the execution of [code] that has been written by a single programmer or team of programmers, which is tested in isolation from the more complete system. - Code Complete 2nd ed.
    • 9. How we end up testing stuff class User{ public function __construct($userName){ //do stuff } public function checkPassword($password){ //do stuff } public function setLogIn(){ //do stuff }
    • 10. How we end up testing stuff $u = new User(‘davidhaskins@ieee.org’); //test to fail $u->checkPassword(‘bad_password’); //test to succeed $u->checkPassword(‘s3kr3t_p@sswd’);
    • 11. How we end up testing stuff $u = new User(‘davidhaskins@ieee.org’); //test to fail if($u->checkPassword(‘bad_password’) === false){ echo ‘successfully rejected’; } //test to succeed if($u->checkPassword(‘s3kr3t_p@sswd’) === true){ echo ‘successfully accepted’; }
    • 12. What do we do with this information?
    • 13. What do we do with this information? We delete it!!!
    • 14. What do we do with this information? We delete it!!! (or, at best, we comment it out)
    • 15. PHPUnit • a framework for unit testing PHP • excellent documentation at http://phpunit.de • easy to setup
    • 16. Installing PHPUnit • Pear • Composer (preferred method)
    • 17. Installing PHPUnit pear config-set audto_discover 1 pear install pear.phpunit.de/PHPUnit
    • 18. Installing PHPUnit Composer can be used to download and install “dependencies”(other libraries and such). download composer: curl -s http://getcomposer.org/installer | php
    • 19. Installing PHPUnit create a file named composer.json containing: { “require-dev”: { “phpunit/phpunit”: “3.7.4” } }
    • 20. Installing PHPUnit run: ./composer.phar update (a .phar file is a “PHP Archive” file.)
    • 21. Installing PHPUnit create a file named phpunit.xml containing: <?xml version="1.0" encoding="UTF-8"?><phpunit colors="true"> <testsuites> <testsuite name="Application Test Suite"> <directory>./phpUnitTutorial/Test/</directory> </testsuite> </testsuites></phpunit>
    • 22. Running PHPUnit ./vendor/bin/phpunit
    • 23. Running PHPUnit ./vendor/bin/phpunit
    • 24. A simple PHPUnit test
    • 25. class myTest extends PHPUnitTest_Framework_TestCase { }
    • 26. class myTest extends PHPUnitTest_Framework_TestCase { public function someSimpleTest(){ } }
    • 27. class myTest extends PHPUnitTest_Framework_TestCase { public function someSimpleTest(){ $myVar = true; $this->assertTrue($myVar); } }
    • 28. class myTest extends PHPUnitTest_Framework_TestCase { public function someSimpleTest(){ $myVar = true; $this->assertTrue($myVar); } public function anotherSimpleTest(){ $myVar = false; $this->assertTrue($myvar); //fails }
    • 29. PHPUnit offers: assertTrue(); assertFalse(); assertEquals(); assertArrayHasKey(); assertStringEndsWith(); ...and many more!
    • 30. The next few examples are from Juan Treminio’s tutorial: https://jtreminio.com/2013/03
    • 31. The phrase “slugify” means to change something like this: The quick BROWN fox @ noon into this: the-quick-brown-fox-noon
    • 32. <?phpclass URL { public function sluggify($string, $separator = '-', $maxLength = 96) { $title = iconv('UTF-8', 'ASCII//TRANSLIT', $string); $title = preg_replace("%[^-/+|w ]%", '', $title); $title = strtolower(trim(substr($title, 0, $maxLength), '-')); $title = preg_replace("/[/_|+ -]+/", $separator, $title); return $title; } }
    • 33. Let’s write a test for it!
    • 34. namespace phpUnitTutorialTest;use phpUnitTutorialURL;class URLTest extends PHPUnit_Framework_TestCase { }
    • 35. namespace phpUnitTutorialTest;use phpUnitTutorialURL;class URLTest extends PHPUnit_Framework_TestCase { public function testSluggifyReturnsSluggifiedString() { $originalString = 'This string will be sluggified'; $expectedResult = 'this-string-will-be-sluggified'; } }
    • 36. namespace phpUnitTutorialTest;use phpUnitTutorialURL;class URLTest extends PHPUnit_Framework_TestCase { public function testSluggifyReturnsSluggifiedString() { $originalString = 'This string will be sluggified'; $expectedResult = 'this-string-will-be-sluggified'; $url = new URL(); $result = $url->sluggify($originalString); } }
    • 37. namespace phpUnitTutorialTest;use phpUnitTutorialURL;class URLTest extends PHPUnit_Framework_TestCase { public function testSluggifyReturnsSluggifiedString() { $originalString = 'This string will be sluggified'; $expectedResult = 'this-string-will-be-sluggified'; $url = new URL(); $result = $url->sluggify($originalString); $this->assertEquals($expectedResult, $result); } }
    • 38. We have a unit test!
    • 39. Other tests we can add public function testSluggifyReturnsExpectedForStringsContainingNumbers() { $originalString = 'This1 string2 will3 be 44 sluggified10'; $expectedResult = 'this1-string2-will3-be-44-sluggified10'; $url = new URL(); $result = $url->sluggify($originalString); $this->assertEquals($expectedResult, $result); }
    • 40. Other tests we can add public function testSluggifyReturnsExpectedForStringsContainingSpecialCharacters() { $originalString = 'This! @string#$ %$will ()be "sluggified'; $expectedResult = 'this-string-will-be-sluggified'; $url = new URL(); $result = $url->sluggify($originalString); $this->assertEquals($expectedResult, $result); }
    • 41. Other tests we can add public function testSluggifyReturnsExpectedForStringsContainingNonEnglishCharacters() { $originalString = "Tänk efter nu – förr'n vi föser dig bort"; $expectedResult = 'tank-efter-nu-forrn-vi-foser-dig-bort'; $url = new URL(); $result = $url->sluggify($originalString); $this->assertEquals($expectedResult, $result); }
    • 42. Other tests we can add public function testSluggifyReturnsExpectedForEmptyStrings() { $originalString = ''; $expectedResult = ''; $url = new URL(); $result = $url->sluggify($originalString); $this->assertEquals($expectedResult, $result); }
    • 43. That’s neat, but it seems we are writing the same code over and over.
    • 44. That’s neat, but it seems we are writing the same code over and over. We can use the “dataProvider annotation.”
    • 45. That’s neat, but it seems we are writing the same code over and over. We can use the “dataProvider annotation.” Annotations are described in docblocks (comments) of methods.
    • 46. class URLTest extends PHPUnit_Framework_TestCase { /** * @dataProvider providerTestSluggifyReturnsSluggifiedString */ public function testSluggifyReturnsSluggifiedString($originalString, $expectedResult) { //do our assertion here } public function providerTestSluggifyReturnsSluggifiedString() { //return an array of arrays which contains our data } }
    • 47. class URLTest extends PHPUnit_Framework_TestCase { /** * @dataProvider providerTestSluggifyReturnsSluggifiedString */ public function testSluggifyReturnsSluggifiedString($originalString, $expectedResult) { $url = new URL(); $result = $url->sluggify($originalString); $this->assertEquals($expectedResult, $result); } public function providerTestSluggifyReturnsSluggifiedString() { return array( array('This string will be sluggified', 'this-string-will-be-sluggified'), array('THIS STRING WILL BE SLUGGIFIED', 'this-string-will-be-sluggified'), array('This1 string2 will3 be 44 sluggified10', 'this1-string2-will3-be-44-sluggified10'), array('This! @string#$ %$will ()be "sluggified', 'this-string-will-be-sluggified'), array("Tänk efter nu – förr'n vi föser dig bort", 'tank-efter-nu-forrn-vi-foser-dig-bort'), array('', ''), ); } }
    • 48. I haven’t been honest here URL::Sluggify() was deceptively simple it; had no dependencies.
    • 49. When you're doing testing like this, you're focusing on one element of the software at a time -hence the common term unit testing. The problem is that to make a single unit work, you often need other units... - Martin Fowler http://martinfowler.com/articles/mocksArentStubs.html
    • 50. What happens when we depend on other stuff (databases, other objects, etc.)?
    • 51. setUp() and tearDown() class FoobarTest extends PHPUnit_Framework_Testcase{ public function setUp(){ //do things before these tests run // copy a production database into a test db // instantiate objects // define constants } public function tearDown(){ //do things after the tests run // delete test db } }
    • 52. But we still have problems Databases can go down which could cause our tests to fail. Instantiating objects can be slow which could make testing take forever (we want to be able to test often). ...and we want isolation!
    • 53. “Mocks and stubs” to the rescue!
    • 54. We may have to jump through some hoops, but we’ll get there!
    • 55. Stubs //a method with stuff (implementation details irrelevant) public function doSomething($param1, $param2){ mysql_connect("your.hostaddress.com", $param1, $param2) or die(mysql_error()); mysql_select_db("address") or die(mysql_error()); !(isset($pagenum)) ? $pagenum = 1 : $pagenum=0; $data = mysql_query("SELECT * FROM topsites") or die(mysql_error()); $rows = mysql_num_rows($data); $page_rows = 4; $last = ceil($rows/$page_rows); $pagenum < 1 ? $pagenum=1 : $pagenum = $last; $max = 'limit ' .($pagenum - 1) * $page_rows .',' .$page_rows; return $max; }
    • 56. Stubs //a method with stuff (implementation details irrelevant) public function StubDoSomething($param1, $param2){ return null; }
    • 57. Mock objects Mock Objects: objects pre-programmed with expectations which form a specification of the calls they are expected to receive.
    • 58. Mock objects Let’s look at an example.
    • 59. Mock objects class User{ public function __construct($id){ $this-> id = $id; } public function verifyUser(){ //validate against an LDAP server } public function getName(){ //get user name from the LDAP server }
    • 60. Mock objects class ForumPost{ public function deletePostsByUser($user){ $user_id = $user->getUserID(); $query = “delete from posts where userID = ? ”; ….//do stuff } //...other methods }
    • 61. require_once ‘User.php’; require_once ‘ForumPost.php’; class testForum extends PHPUnitTest_Framework_TestCase { public function testUserPostDelete(){ $user = new User(7); $userName = $user->getName(); $post = new ForumPost(); $rowsDeleted = $post->deletePostsByUser($user); $message = “$rowsDeleted posts removed for $userName”; $expectedMessage = “5 posts removed for David Haskins”; $this->assertEquals($message,$expectedMessage); } }
    • 62. require_once ‘User.php’; require_once ‘ForumPost.php’; class testForum extends PHPUnitTest_Framework_TestCase { public function testUserPostDelete(){ $user = new User(7); //fails when LDAP server is down! $userName = $user->getName(); $post = new ForumPost(); $rowsDeleted = $post->deletePostsByUser($user); $message = “$rowsDeleted posts removed for $userName”; $expectedMessage = “5 posts removed for David Haskins”; $this->assertEquals($message,$expectedMessage); } }
    • 63. require_once ‘User.php’; require_once ‘ForumPost.php’; class testForum extends PHPUnitTest_Framework_TestCase { public function testUserPostDelete(){ $user = $this->getMockBuilder(‘User’) ->setConstructorArgs(array(7)) ->getMock(); $user->expects($this->once()) ->method(‘getName’) ->will($this->returnValue(‘David Haskins’); $userName = $user->getName(); $post = new ForumPost(); $rowsDeleted = $post->deletePostsByUser($user); $message = “$rowsDeleted posts removed for $userName”; $expectedMessage = “5 posts removed for David Haskins”; $this->assertEquals($message,$expectedMessage); }
    • 64. TDD Test Driven Development is a method of developing code by writing the tests FIRST!
    • 65. TDD
    • 66. Git and unit tests You can add client or server side “hooks” to git to run your unit tests and reject submissions that fail the unit tests. http://www.masnun.com/2012/03/18/running-phpunit-on-git-hook.html
    • 67. Coverage report tool ./vendor/bin/phpunit --coverage-html coverage
    • 68. bool underAttack = false; underAttack = detectEvents(); //do some other stuff if(underAttack = true) { launchNuclearMissles(); } else { alert(“false alarm!”); }
    • 69. Other Texts to Consider https://jtreminio.com/2013/03 http://phpunit.de