SlideShare a Scribd company logo
1 of 56
Download to read offline
South Florida PHP Meetup Group
   James Fuller
   Web Developer
   http://www.jblotus.com

   Started unit testing in response to a new job
    developing on a large, buggy legacy
    application used by millions
   Afraid to make even tiny code changes due to
    unpredictable side-effects?

   Been burned by bugs that came back to life?

   Does sketchy code keep you up at night?
Imagine your code as a dark twisted forest that
you must navigate.

Nothing makes sense, there are no clear paths
and you are surrounded by bugs. Lots of bugs.

How would you handle being stuck in this
situation?
   Some will be brave and foolish, cutting
    corners to move quickly through the
    forest.

   Some will be paralyzed by the thought
    of making the wrong move.

   Most will succumb to the bugs or die a
    horrible death trying to find a way out.
Modify code


  Broke
something                  Run feature




God I hope                 Doesn't work
this works

             Modify Code
   Write tests
   Use PHPUnit to automate your tests
   Practice Test-Driven-Development
   Improve your design
   Enjoy the added value
   Can you prove it works? automatically?

   Can you change it and know it still works?
    without loading the browser?

   Can you promise that if it breaks, it will never
    break like that again?

   What about edge cases? You do care about
    edge cases, right?
   All developers practice some form of testing.
    Most PHP developers do it in the browser.

   What we want to do is automate testing
    with PHPUnit.

   Don't confuse apathy with laziness. Good
    coders automate repetitive tasks because
    they are lazy.
   Before you write new code
   When you fix a bug
   Before you begin refactoring code
   As you go, improving code coverage

We can use Test-Driven-Development to help
us maintain disclipline in writing our unit tests.
   The principle of unit testing is to verify that a
    unit of code will function correctly in
    isolation.

   A unit is the smallest testable part of an
    application, usually a function or method.
Understand
            Requirements


Refactor                   Write tests



Run Tests                   Run Tests
 (PASS)                      (FAIL)


             Write Code
   Focus on design of system before
    implementation
   Changes are easier to make, with less side
    effects
   Documentation via example
   Less FEAR, more CONFIDENCE
   You have tests at the end!
   PHPUnit is an automated testing framework
    PHP development based upon xUnit (java).

   PHPUnit gives us an easy way to write tests,
    generate code coverage and improve the
    quality of our code.
Command line test runner
Mature and expansive assertion library
Code coverage
Mock objects
Lots of extensions
Fast & Configurable
   PEAR
     best for system wide access to phpunit
     hard to downgrade or change versions
     dependencies can be tricky

   Github
     allows the most control
     easy to pack up in your version control system
     lots of steps


   Phar (PHP Archive)
     a single phar can be easily included in your projects
     in development
     many features don't work or don't work as expected
   Upgrade PEAR to the latest version
     sudo pear upgrade PEAR



   Install PHPUnit
     pear config-set auto_discover  1
     pear install pear.phpunit.de/PHPUnit


   This will install the latest release of PHPUnit.

   Installing older versions is a bit trickier.
   pear   install   phpunit/DbUnit
   pear   install   phpunit/PHPUnit_Selenium
   pear   install   phpunit/PHPUnit_Story
   pear   install   phpunit/PHPUnit_TestListener_DBUS
   pear   install   phpunit/PHPUnit_TestListener_DBUS
   pear   install   phpunit/PHPUnit_TestListener_XHProf
   pear   install   phpunit/PHPUnit_TicketListener_Fogbugz
   pear   install   phpunit/PHPUnit_TicketListener_GitHub
   pear   install   phpunit/PHPUnit_TicketListener_GoogleCode
   pear   install   phpunit/PHPUnit_TicketListener_Trac
   pear   install   phpunit/PHP_Invoker
   Checkout source from github
    mkdir phpunit && cd phpunit
    git clone git://github.com/sebastianbergmann/phpunit.git
    git clone git://github.com/sebastianbergmann/dbunit.git
    …

   Still need PEAR to install YAML component
    pear install pear.symfony-project.com/YAML

   Make sure to add all these directories to your include_path

   Checking out specific versions of packages:
    cd phpunit
    git checkout 3.6
   Usage
     phpunit [switches] UnitTest [UnitTest.php]
     phpunit [switches] <directory>

   Common Switches
       --stop-on-error          Stop upon first error.
       --stop-on-failure        Stop upon first error or failure.
       --debug                  Output debug info (test name)
       -v|--verbose             Output verbose information.
       --bootstrap <file>       Load this file before tests
       --configuration <file>   Specify config file
                                 (default phpunix.xml)
   PHPUnit runtime options can be defined
    using command line switches and/or xml
    (phpunit.xml)

   Bootstrap your application as needed before
    tests run (bootstrap.php)

   Define paths for code coverage output, logs,
    etc.
It's easy!! Include the autoloader in your
bootstrap or in your test cases:

<?php
require_once 'PHPUnit/Autoload.php';
   A test suite contains any number of test
    cases.

   A test case is a class that contains individual
    tests.

   A test is a method that contains the code to
    test something.
/
    lib/
     Foo.php

    tests/
      suite/
       lib/
       FooTest.php
<phpunit>
  <testsuites>
    <testsuite name="All Tests">
      <directory>tests/suite</directory>
    </testsuite>
    <testsuite name="Some Tests">
      <file>tests/suite/FooTest.php</file>
      <file>tests/suite/BarTest.php</file>
    </testsuite>
  </testsuites>
</phpunit>
A Fixture represents the known state of the
world.

   Object instantiation
   Database Records
   Preconditions & Postconditions

PHPUnit offers several built-in methods to
reduce the clutter of setting up fixtures.
class FooTest extends PHPUnit_Framework_TestCase {

    //runs before each test method
    protected function setUp() {}

    //runs after each test method
    protected function tearDown() {}

    //runs before any tests
    public static function setUpBeforeClass() {}

    //runs after all tests
    public static function tearDownAfterClass() {}
}
class FooTest extends PHPUnit_Framework_TestCase {
  protected $Foo;

    protected function setUp() {
      $this->Foo = new Foo;
    }

    public function testFoo () {
      $this->assertNull($this->Foo->method());
    }

    public function testFoo1() {
      $this->assertNull($this->Foo->otherMethod());
    }
}
//method being tested in class Foo
public function reverseConcat($a, $b) {
  return strrev($a . $b);
}

//test method in class FooTest
public function testReverseConcat() {
  $sut = new Foo;
  $actual = $sut->reverseConcat('Foo', 'Bar');
  $expected = 'raBooF';
  $this->assertEquals($expected, $actual);
}
   An assertion is how we declare an expectation.

   Well-tested systems rely upon verification, not
    developer intuition.

   Things we can assert with PHPUnit
     return values
     certain methods/objects were called via Test Doubles
     echo/print output
assertArrayHasKey()               assertNull()
assertClassHasAttribute()         assertObjectHasAttribute()
assertClassHasStaticAttribute()   assertRegExp()
assertContains()                  assertStringMatchesFormat()
assertContainsOnly()              assertStringMatchesFormatFile()
assertCount()                     assertSame()
assertEmpty()                     assertSelectCount()
assertEqualXMLStructure()         assertSelectEquals()
assertEquals()                    assertSelectRegExp()
assertFalse()                     assertStringEndsWith()
assertFileEquals()                assertStringEqualsFile()
assertFileExists()                assertStringStartsWith()
assertGreaterThan()               assertTag()
assertGreaterThanOrEqual()        assertThat()
assertInstanceOf()                assertTrue()
assertInternalType()              assertXmlFileEqualsXmlFile()
assertLessThan()                  assertXmlStringEqualsXmlFile()
assertLessThanOrEqual()           assertXmlStringEqualsXmlString()
When assertions evaluate to TRUE the test will emit a PASS


 $this->assertTrue(true);
 $this->assertFalse(false);
 $this->assertEquals('foo', 'foo');
 $this->assertEmpty(array());

 $this->assertNotIsSame(new stdClass, new stdClass);

 $this->assertArrayHasKey('foo', array('foo' => 'bar'));

 $this->assertCount(2, array('apple', 'orange'));
When assertions evaluate to FALSE the test will emit a FAILURE


$this->assertTrue(false);
$this->assertFalse(true);
$this->assertEquals('foo', 'bar');
$this->assertEmpty(array('foo'));

$this->assertIsSame(new stdClass, new stdClass);

$this->assertArrayHasKey('foo', array());

$this->assertCount(2, array('apple'));
   game has 2 players
   players pick either rock, paper, or scissors
   rock beats scissors
   paper beats rock
   scissors beats paper
   round is a draw if both players pick the same
    object
   Isolation means that a unit of code is not
    affected by external factors.

   In practice we can't always avoid external
    dependencies, but we benefit from trying to
    reduce their impact on our tests.

   This means we need to be able to substitute
    external dependencies with test doubles.
   Test doubles are objects we use to substitute
    dependencies in our system under test.

   Stubs return prebaked values when it's
    methods are called.

   Mocks are like programmable stubs. You can
    verify that methods are called correctly and
    perform more complex verification.
   PHPUnit provides a built in mocking
    framework.

   You can easily create test doubles that you
    can inject into your system under test.

   This allows you to swap out complex
    dependencies with controllable and
    verifiable objects.
public function testStub() {

    $stub = $this->getMock('Stub', array('foo'));

    $stub->expects($this->once())
         ->method('foo')
         ->will($this->returnValue('bar'));

    $actual = $stub->foo();

  $this->assertEquals('bar', $actual, "should
have returned 'bar'");

}
   Two ways to generate mock objects
   getMock() with arguments
   Mock Builder API
$this->getMock(
   $class_name,
   $mocked_methods,
   $constructor_args,
   $mock_class_name,
   $call_original_constructor,
   $call_original_clone_constructor,
   $disable_autoload
);
$this->getMockBuilder($class_name)
     ->setMethods(array $methods)
     ->disableOriginalConstructor()
     ->disableOriginalClone()
     ->setConstructorArgs(array $args)
     ->setMockClassName($class_name)
     ->getMock();
$mock = $this->getMockBuilder('Foo')
             ->setMethods(array('someMethod'))
             ->getMock();

$mock->expects($this->any())
     ->method('someMethod')
     ->will(
         $this->onConsecutiveCalls('bar', 'baz')
      );

$mock->someMethod(); //returns 'bar'
$mock->someMethod(); //returns 'baz'
$mock = $this->getMockBuilder('Foo')
             ->setMethods(array('someMethod'))
             ->getMock();

$mock->expects($this->any())
     ->method('someMethod')
     ->will($this->throwException(
        new RuntimeException
      ));

//throws a RuntimeException
$mock->someMethod();
class WebService {
  protected $Http;

    public function __construct(Http $http) {
      $this->Http = $http;
    }

    public function getUrl($url = '') {
      return $this->Http->get($url);
    }
}
require_once 'PHPUnit/Autoload.php';
require_once 'WebService.php';

class TestWebService extends PHPUnit_Framework_TestCase {

    public function testGetUrl_callsHttpCorrectly() {

        $http = $this->getMockBuilder('FakeClassName')
                     ->setMethods(array('get'))
                     ->setMockClassName('Http')
                     ->getMock();

        $http->expects($this->once())
             ->method('get')
             ->with($url);

        //inject the mock via constructor
        $sut = new WebService($http);

        //test Http get
        $sut->getUrl('http://google.com');
    }
}
   Static method calls

   Instantiating objects directly (hard
    coupling)

   External resources (network, file system)

   Globals ($_GLOBALS, Singletons)
class Dependency {
}

class SystemUnderTest {

    public function badIdea() {
      $dependency = new Dependency;
    }
}
class TwitterClient {

    function getTweets() {
      $url = 'api.twitter.com/v2/tweets/...';
      return Http::consume($url);
    }
}
class TwitterClient {

    protected $Http;

    public function __construct(Http $http) {
      $this->Http = $http;
    }

    public function getTweets() {
      $url = 'api.twitter.com/v2/tweets/...';
      return $this->Http->consume($url);
    }
}
class TestTwitterClient extends
PHPUnit_Framework_TestCase {

    public function testCantMockTwitter() {

        $mock = $this->getMockBuilder(Http')
                     ->setMethods(array('consume'))
                     ->getMock();

        $sut = new TwitterClient($mock);
        $sut->getTweets();
    }
}
class Singleton {

    public $data;
    protected static $instance;

    private function __construct() {}
    private function __clone() {}

    public function getInstance() {
      if (!self::$instance) {
        self::$instance = new self;
      }
      return self::$instance;
    }
}
class SystemUnderTest {

    public function setData($data) {
      Singleton::getInstance()->data = $data;
    }

    public function getData() {
      return Singleton::getInstance()->data;
    }
}
class TestSystemUnderTest extends
PHPUnit_Framework_TestCase {

    public function testSingletonsAreFineAtFirst() {

        $sut = new SystemUnderTest;
        $sut->setData('foo');

        //passes
        $this->assertEquals('foo', $sut->getData());
    }

    public function testSingletonsNeverDie() {

        $sut = new SystemUnderTest;
        $actual = $sut->getData();

        //fails
        $this->assertNull($actual);
    }
}
   Many frameworks come with built in testing
    facilities, or the ability to easily integrate with
    PHPUnit.

   Try to use the built-in testing tools. They
    usually do the heavy lifting of bootstrapping
    your application.
   Get your test harness working
   Get your feet wet first, testing smaller/trivial
    code
   Manual verification is prudent
   Improve your design, refactor
   Write tests for new code
   Write tests opportunistically
Fighting Fear-Driven-Development With PHPUnit

More Related Content

What's hot

Caching and tuning fun for high scalability @ FrOSCon 2011
Caching and tuning fun for high scalability @ FrOSCon 2011Caching and tuning fun for high scalability @ FrOSCon 2011
Caching and tuning fun for high scalability @ FrOSCon 2011Wim Godden
 
Vagrant move over, here is Docker
Vagrant move over, here is DockerVagrant move over, here is Docker
Vagrant move over, here is DockerNick Belhomme
 
Learn flask in 90mins
Learn flask in 90minsLearn flask in 90mins
Learn flask in 90minsLarry Cai
 
The why and how of moving to php 5.4
The why and how of moving to php 5.4The why and how of moving to php 5.4
The why and how of moving to php 5.4Wim Godden
 
Quick flask an intro to flask
Quick flask   an intro to flaskQuick flask   an intro to flask
Quick flask an intro to flaskjuzten
 
Automation testing with Drupal 8
Automation testing with Drupal 8Automation testing with Drupal 8
Automation testing with Drupal 8nagpalprachi
 
Top 50 Interview Questions and Answers in CakePHP
Top 50 Interview Questions and Answers in CakePHPTop 50 Interview Questions and Answers in CakePHP
Top 50 Interview Questions and Answers in CakePHPKetan Patel
 
2 introduction-php-mvc-cakephp-m2-installation-slides
2 introduction-php-mvc-cakephp-m2-installation-slides2 introduction-php-mvc-cakephp-m2-installation-slides
2 introduction-php-mvc-cakephp-m2-installation-slidesMasterCode.vn
 
SDPHP - Percona Toolkit (It's Basically Magic)
SDPHP - Percona Toolkit (It's Basically Magic)SDPHP - Percona Toolkit (It's Basically Magic)
SDPHP - Percona Toolkit (It's Basically Magic)Robert Swisher
 
PHP 5.6 New and Deprecated Features
PHP 5.6  New and Deprecated FeaturesPHP 5.6  New and Deprecated Features
PHP 5.6 New and Deprecated FeaturesMark Niebergall
 
Automated php unit testing in drupal 8
Automated php unit testing in drupal 8Automated php unit testing in drupal 8
Automated php unit testing in drupal 8Jay Friendly
 
Debugging PHP with Xdebug - PHPUK 2018
Debugging PHP with Xdebug - PHPUK 2018Debugging PHP with Xdebug - PHPUK 2018
Debugging PHP with Xdebug - PHPUK 2018Mark Niebergall
 
LvivPy - Flask in details
LvivPy - Flask in detailsLvivPy - Flask in details
LvivPy - Flask in detailsMax Klymyshyn
 
Learning Puppet Chapter 1
Learning Puppet Chapter 1Learning Puppet Chapter 1
Learning Puppet Chapter 1Vishal Biyani
 
Release with confidence
Release with confidenceRelease with confidence
Release with confidenceJohn Congdon
 

What's hot (20)

Caching and tuning fun for high scalability @ FrOSCon 2011
Caching and tuning fun for high scalability @ FrOSCon 2011Caching and tuning fun for high scalability @ FrOSCon 2011
Caching and tuning fun for high scalability @ FrOSCon 2011
 
Vagrant move over, here is Docker
Vagrant move over, here is DockerVagrant move over, here is Docker
Vagrant move over, here is Docker
 
Learn flask in 90mins
Learn flask in 90minsLearn flask in 90mins
Learn flask in 90mins
 
Laravel Unit Testing
Laravel Unit TestingLaravel Unit Testing
Laravel Unit Testing
 
The why and how of moving to php 5.4
The why and how of moving to php 5.4The why and how of moving to php 5.4
The why and how of moving to php 5.4
 
Getting testy with Perl
Getting testy with PerlGetting testy with Perl
Getting testy with Perl
 
Effective Benchmarks
Effective BenchmarksEffective Benchmarks
Effective Benchmarks
 
Quick flask an intro to flask
Quick flask   an intro to flaskQuick flask   an intro to flask
Quick flask an intro to flask
 
Automation testing with Drupal 8
Automation testing with Drupal 8Automation testing with Drupal 8
Automation testing with Drupal 8
 
Top 50 Interview Questions and Answers in CakePHP
Top 50 Interview Questions and Answers in CakePHPTop 50 Interview Questions and Answers in CakePHP
Top 50 Interview Questions and Answers in CakePHP
 
2 introduction-php-mvc-cakephp-m2-installation-slides
2 introduction-php-mvc-cakephp-m2-installation-slides2 introduction-php-mvc-cakephp-m2-installation-slides
2 introduction-php-mvc-cakephp-m2-installation-slides
 
SDPHP - Percona Toolkit (It's Basically Magic)
SDPHP - Percona Toolkit (It's Basically Magic)SDPHP - Percona Toolkit (It's Basically Magic)
SDPHP - Percona Toolkit (It's Basically Magic)
 
PHP 5.6 New and Deprecated Features
PHP 5.6  New and Deprecated FeaturesPHP 5.6  New and Deprecated Features
PHP 5.6 New and Deprecated Features
 
Unit Testing Lots of Perl
Unit Testing Lots of PerlUnit Testing Lots of Perl
Unit Testing Lots of Perl
 
Automated php unit testing in drupal 8
Automated php unit testing in drupal 8Automated php unit testing in drupal 8
Automated php unit testing in drupal 8
 
Debugging PHP with Xdebug - PHPUK 2018
Debugging PHP with Xdebug - PHPUK 2018Debugging PHP with Xdebug - PHPUK 2018
Debugging PHP with Xdebug - PHPUK 2018
 
Getting Testy With Perl6
Getting Testy With Perl6Getting Testy With Perl6
Getting Testy With Perl6
 
LvivPy - Flask in details
LvivPy - Flask in detailsLvivPy - Flask in details
LvivPy - Flask in details
 
Learning Puppet Chapter 1
Learning Puppet Chapter 1Learning Puppet Chapter 1
Learning Puppet Chapter 1
 
Release with confidence
Release with confidenceRelease with confidence
Release with confidence
 

Similar to Fighting Fear-Driven-Development With PHPUnit

Automated Unit Testing
Automated Unit TestingAutomated Unit Testing
Automated Unit TestingMike Lively
 
Unit Testing using PHPUnit
Unit Testing using  PHPUnitUnit Testing using  PHPUnit
Unit Testing using PHPUnitvaruntaliyan
 
Test Driven Development with PHPUnit
Test Driven Development with PHPUnitTest Driven Development with PHPUnit
Test Driven Development with PHPUnitMindfire Solutions
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Michelangelo van Dam
 
Unit Testing in PHP
Unit Testing in PHPUnit Testing in PHP
Unit Testing in PHPRadu Murzea
 
Unit testing php-unit - phing - selenium_v2
Unit testing   php-unit - phing - selenium_v2Unit testing   php-unit - phing - selenium_v2
Unit testing php-unit - phing - selenium_v2Tricode (part of Dept)
 
PHPUnit: from zero to hero
PHPUnit: from zero to heroPHPUnit: from zero to hero
PHPUnit: from zero to heroJeremy Cook
 
PHPUnit with CakePHP and Yii
PHPUnit with CakePHP and YiiPHPUnit with CakePHP and Yii
PHPUnit with CakePHP and Yiimadhavi Ghadge
 
PHPUnit best practices presentation
PHPUnit best practices presentationPHPUnit best practices presentation
PHPUnit best practices presentationThanh Robi
 
Unlock The Mystery Of PHPUnit (Wave PHP 2018)
Unlock The Mystery Of PHPUnit (Wave PHP 2018)Unlock The Mystery Of PHPUnit (Wave PHP 2018)
Unlock The Mystery Of PHPUnit (Wave PHP 2018)ENDelt260
 
Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Michelangelo van Dam
 
Unit testing for WordPress
Unit testing for WordPressUnit testing for WordPress
Unit testing for WordPressHarshad Mane
 
Getting started with PHPUnit
Getting started with PHPUnitGetting started with PHPUnit
Getting started with PHPUnitKhyati Gala
 
Introduction to PowerShell
Introduction to PowerShellIntroduction to PowerShell
Introduction to PowerShellBoulos Dib
 
Test in action week 2
Test in action   week 2Test in action   week 2
Test in action week 2Yi-Huan Chan
 

Similar to Fighting Fear-Driven-Development With PHPUnit (20)

Automated Unit Testing
Automated Unit TestingAutomated Unit Testing
Automated Unit Testing
 
Unit Testing using PHPUnit
Unit Testing using  PHPUnitUnit Testing using  PHPUnit
Unit Testing using PHPUnit
 
Unit testing
Unit testingUnit testing
Unit testing
 
Test Driven Development with PHPUnit
Test Driven Development with PHPUnitTest Driven Development with PHPUnit
Test Driven Development with PHPUnit
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12
 
Unit Testing in PHP
Unit Testing in PHPUnit Testing in PHP
Unit Testing in PHP
 
Unit testing php-unit - phing - selenium_v2
Unit testing   php-unit - phing - selenium_v2Unit testing   php-unit - phing - selenium_v2
Unit testing php-unit - phing - selenium_v2
 
Phpunit testing
Phpunit testingPhpunit testing
Phpunit testing
 
PHPUnit: from zero to hero
PHPUnit: from zero to heroPHPUnit: from zero to hero
PHPUnit: from zero to hero
 
PHPUnit with CakePHP and Yii
PHPUnit with CakePHP and YiiPHPUnit with CakePHP and Yii
PHPUnit with CakePHP and Yii
 
PHPUnit best practices presentation
PHPUnit best practices presentationPHPUnit best practices presentation
PHPUnit best practices presentation
 
Unlock The Mystery Of PHPUnit (Wave PHP 2018)
Unlock The Mystery Of PHPUnit (Wave PHP 2018)Unlock The Mystery Of PHPUnit (Wave PHP 2018)
Unlock The Mystery Of PHPUnit (Wave PHP 2018)
 
Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012
 
Unit testing for WordPress
Unit testing for WordPressUnit testing for WordPress
Unit testing for WordPress
 
Getting started with PHPUnit
Getting started with PHPUnitGetting started with PHPUnit
Getting started with PHPUnit
 
Unit testing
Unit testingUnit testing
Unit testing
 
Junit_.pptx
Junit_.pptxJunit_.pptx
Junit_.pptx
 
Introduction to PowerShell
Introduction to PowerShellIntroduction to PowerShell
Introduction to PowerShell
 
Test in action week 2
Test in action   week 2Test in action   week 2
Test in action week 2
 
PHPUnit
PHPUnitPHPUnit
PHPUnit
 

Recently uploaded

Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Angeliki Cooney
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...apidays
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxRustici Software
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWERMadyBayot
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistandanishmna97
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Orbitshub
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FMESafe Software
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024The Digital Insurer
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...Zilliz
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Victor Rentea
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...apidays
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyKhushali Kathiriya
 
Cyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdfCyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdfOverkill Security
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Victor Rentea
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...apidays
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesrafiqahmad00786416
 

Recently uploaded (20)

Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Cyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdfCyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdf
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 

Fighting Fear-Driven-Development With PHPUnit

  • 1. South Florida PHP Meetup Group
  • 2. James Fuller  Web Developer  http://www.jblotus.com  Started unit testing in response to a new job developing on a large, buggy legacy application used by millions
  • 3. Afraid to make even tiny code changes due to unpredictable side-effects?  Been burned by bugs that came back to life?  Does sketchy code keep you up at night?
  • 4. Imagine your code as a dark twisted forest that you must navigate. Nothing makes sense, there are no clear paths and you are surrounded by bugs. Lots of bugs. How would you handle being stuck in this situation?
  • 5. Some will be brave and foolish, cutting corners to move quickly through the forest.  Some will be paralyzed by the thought of making the wrong move.  Most will succumb to the bugs or die a horrible death trying to find a way out.
  • 6. Modify code Broke something Run feature God I hope Doesn't work this works Modify Code
  • 7. Write tests  Use PHPUnit to automate your tests  Practice Test-Driven-Development  Improve your design  Enjoy the added value
  • 8. Can you prove it works? automatically?  Can you change it and know it still works? without loading the browser?  Can you promise that if it breaks, it will never break like that again?  What about edge cases? You do care about edge cases, right?
  • 9. All developers practice some form of testing. Most PHP developers do it in the browser.  What we want to do is automate testing with PHPUnit.  Don't confuse apathy with laziness. Good coders automate repetitive tasks because they are lazy.
  • 10. Before you write new code  When you fix a bug  Before you begin refactoring code  As you go, improving code coverage We can use Test-Driven-Development to help us maintain disclipline in writing our unit tests.
  • 11. The principle of unit testing is to verify that a unit of code will function correctly in isolation.  A unit is the smallest testable part of an application, usually a function or method.
  • 12. Understand Requirements Refactor Write tests Run Tests Run Tests (PASS) (FAIL) Write Code
  • 13. Focus on design of system before implementation  Changes are easier to make, with less side effects  Documentation via example  Less FEAR, more CONFIDENCE  You have tests at the end!
  • 14. PHPUnit is an automated testing framework PHP development based upon xUnit (java).  PHPUnit gives us an easy way to write tests, generate code coverage and improve the quality of our code.
  • 15. Command line test runner Mature and expansive assertion library Code coverage Mock objects Lots of extensions Fast & Configurable
  • 16. PEAR  best for system wide access to phpunit  hard to downgrade or change versions  dependencies can be tricky  Github  allows the most control  easy to pack up in your version control system  lots of steps  Phar (PHP Archive)  a single phar can be easily included in your projects  in development  many features don't work or don't work as expected
  • 17. Upgrade PEAR to the latest version  sudo pear upgrade PEAR  Install PHPUnit  pear config-set auto_discover 1  pear install pear.phpunit.de/PHPUnit  This will install the latest release of PHPUnit.  Installing older versions is a bit trickier.
  • 18. pear install phpunit/DbUnit  pear install phpunit/PHPUnit_Selenium  pear install phpunit/PHPUnit_Story  pear install phpunit/PHPUnit_TestListener_DBUS  pear install phpunit/PHPUnit_TestListener_DBUS  pear install phpunit/PHPUnit_TestListener_XHProf  pear install phpunit/PHPUnit_TicketListener_Fogbugz  pear install phpunit/PHPUnit_TicketListener_GitHub  pear install phpunit/PHPUnit_TicketListener_GoogleCode  pear install phpunit/PHPUnit_TicketListener_Trac  pear install phpunit/PHP_Invoker
  • 19. Checkout source from github mkdir phpunit && cd phpunit git clone git://github.com/sebastianbergmann/phpunit.git git clone git://github.com/sebastianbergmann/dbunit.git …  Still need PEAR to install YAML component pear install pear.symfony-project.com/YAML  Make sure to add all these directories to your include_path  Checking out specific versions of packages: cd phpunit git checkout 3.6
  • 20. Usage  phpunit [switches] UnitTest [UnitTest.php]  phpunit [switches] <directory>  Common Switches  --stop-on-error Stop upon first error.  --stop-on-failure Stop upon first error or failure.  --debug Output debug info (test name)  -v|--verbose Output verbose information.  --bootstrap <file> Load this file before tests  --configuration <file> Specify config file (default phpunix.xml)
  • 21. PHPUnit runtime options can be defined using command line switches and/or xml (phpunit.xml)  Bootstrap your application as needed before tests run (bootstrap.php)  Define paths for code coverage output, logs, etc.
  • 22. It's easy!! Include the autoloader in your bootstrap or in your test cases: <?php require_once 'PHPUnit/Autoload.php';
  • 23. A test suite contains any number of test cases.  A test case is a class that contains individual tests.  A test is a method that contains the code to test something.
  • 24. / lib/ Foo.php tests/ suite/ lib/ FooTest.php
  • 25. <phpunit> <testsuites> <testsuite name="All Tests"> <directory>tests/suite</directory> </testsuite> <testsuite name="Some Tests"> <file>tests/suite/FooTest.php</file> <file>tests/suite/BarTest.php</file> </testsuite> </testsuites> </phpunit>
  • 26. A Fixture represents the known state of the world.  Object instantiation  Database Records  Preconditions & Postconditions PHPUnit offers several built-in methods to reduce the clutter of setting up fixtures.
  • 27. class FooTest extends PHPUnit_Framework_TestCase { //runs before each test method protected function setUp() {} //runs after each test method protected function tearDown() {} //runs before any tests public static function setUpBeforeClass() {} //runs after all tests public static function tearDownAfterClass() {} }
  • 28. class FooTest extends PHPUnit_Framework_TestCase { protected $Foo; protected function setUp() { $this->Foo = new Foo; } public function testFoo () { $this->assertNull($this->Foo->method()); } public function testFoo1() { $this->assertNull($this->Foo->otherMethod()); } }
  • 29. //method being tested in class Foo public function reverseConcat($a, $b) { return strrev($a . $b); } //test method in class FooTest public function testReverseConcat() { $sut = new Foo; $actual = $sut->reverseConcat('Foo', 'Bar'); $expected = 'raBooF'; $this->assertEquals($expected, $actual); }
  • 30. An assertion is how we declare an expectation.  Well-tested systems rely upon verification, not developer intuition.  Things we can assert with PHPUnit  return values  certain methods/objects were called via Test Doubles  echo/print output
  • 31. assertArrayHasKey() assertNull() assertClassHasAttribute() assertObjectHasAttribute() assertClassHasStaticAttribute() assertRegExp() assertContains() assertStringMatchesFormat() assertContainsOnly() assertStringMatchesFormatFile() assertCount() assertSame() assertEmpty() assertSelectCount() assertEqualXMLStructure() assertSelectEquals() assertEquals() assertSelectRegExp() assertFalse() assertStringEndsWith() assertFileEquals() assertStringEqualsFile() assertFileExists() assertStringStartsWith() assertGreaterThan() assertTag() assertGreaterThanOrEqual() assertThat() assertInstanceOf() assertTrue() assertInternalType() assertXmlFileEqualsXmlFile() assertLessThan() assertXmlStringEqualsXmlFile() assertLessThanOrEqual() assertXmlStringEqualsXmlString()
  • 32. When assertions evaluate to TRUE the test will emit a PASS $this->assertTrue(true); $this->assertFalse(false); $this->assertEquals('foo', 'foo'); $this->assertEmpty(array()); $this->assertNotIsSame(new stdClass, new stdClass); $this->assertArrayHasKey('foo', array('foo' => 'bar')); $this->assertCount(2, array('apple', 'orange'));
  • 33. When assertions evaluate to FALSE the test will emit a FAILURE $this->assertTrue(false); $this->assertFalse(true); $this->assertEquals('foo', 'bar'); $this->assertEmpty(array('foo')); $this->assertIsSame(new stdClass, new stdClass); $this->assertArrayHasKey('foo', array()); $this->assertCount(2, array('apple'));
  • 34. game has 2 players  players pick either rock, paper, or scissors  rock beats scissors  paper beats rock  scissors beats paper  round is a draw if both players pick the same object
  • 35. Isolation means that a unit of code is not affected by external factors.  In practice we can't always avoid external dependencies, but we benefit from trying to reduce their impact on our tests.  This means we need to be able to substitute external dependencies with test doubles.
  • 36. Test doubles are objects we use to substitute dependencies in our system under test.  Stubs return prebaked values when it's methods are called.  Mocks are like programmable stubs. You can verify that methods are called correctly and perform more complex verification.
  • 37. PHPUnit provides a built in mocking framework.  You can easily create test doubles that you can inject into your system under test.  This allows you to swap out complex dependencies with controllable and verifiable objects.
  • 38. public function testStub() { $stub = $this->getMock('Stub', array('foo')); $stub->expects($this->once()) ->method('foo') ->will($this->returnValue('bar')); $actual = $stub->foo(); $this->assertEquals('bar', $actual, "should have returned 'bar'"); }
  • 39. Two ways to generate mock objects  getMock() with arguments  Mock Builder API
  • 40. $this->getMock( $class_name, $mocked_methods, $constructor_args, $mock_class_name, $call_original_constructor, $call_original_clone_constructor, $disable_autoload );
  • 41. $this->getMockBuilder($class_name) ->setMethods(array $methods) ->disableOriginalConstructor() ->disableOriginalClone() ->setConstructorArgs(array $args) ->setMockClassName($class_name) ->getMock();
  • 42. $mock = $this->getMockBuilder('Foo') ->setMethods(array('someMethod')) ->getMock(); $mock->expects($this->any()) ->method('someMethod') ->will( $this->onConsecutiveCalls('bar', 'baz') ); $mock->someMethod(); //returns 'bar' $mock->someMethod(); //returns 'baz'
  • 43. $mock = $this->getMockBuilder('Foo') ->setMethods(array('someMethod')) ->getMock(); $mock->expects($this->any()) ->method('someMethod') ->will($this->throwException( new RuntimeException )); //throws a RuntimeException $mock->someMethod();
  • 44. class WebService { protected $Http; public function __construct(Http $http) { $this->Http = $http; } public function getUrl($url = '') { return $this->Http->get($url); } }
  • 45. require_once 'PHPUnit/Autoload.php'; require_once 'WebService.php'; class TestWebService extends PHPUnit_Framework_TestCase { public function testGetUrl_callsHttpCorrectly() { $http = $this->getMockBuilder('FakeClassName') ->setMethods(array('get')) ->setMockClassName('Http') ->getMock(); $http->expects($this->once()) ->method('get') ->with($url); //inject the mock via constructor $sut = new WebService($http); //test Http get $sut->getUrl('http://google.com'); } }
  • 46. Static method calls  Instantiating objects directly (hard coupling)  External resources (network, file system)  Globals ($_GLOBALS, Singletons)
  • 47. class Dependency { } class SystemUnderTest { public function badIdea() { $dependency = new Dependency; } }
  • 48. class TwitterClient { function getTweets() { $url = 'api.twitter.com/v2/tweets/...'; return Http::consume($url); } }
  • 49. class TwitterClient { protected $Http; public function __construct(Http $http) { $this->Http = $http; } public function getTweets() { $url = 'api.twitter.com/v2/tweets/...'; return $this->Http->consume($url); } }
  • 50. class TestTwitterClient extends PHPUnit_Framework_TestCase { public function testCantMockTwitter() { $mock = $this->getMockBuilder(Http') ->setMethods(array('consume')) ->getMock(); $sut = new TwitterClient($mock); $sut->getTweets(); } }
  • 51. class Singleton { public $data; protected static $instance; private function __construct() {} private function __clone() {} public function getInstance() { if (!self::$instance) { self::$instance = new self; } return self::$instance; } }
  • 52. class SystemUnderTest { public function setData($data) { Singleton::getInstance()->data = $data; } public function getData() { return Singleton::getInstance()->data; } }
  • 53. class TestSystemUnderTest extends PHPUnit_Framework_TestCase { public function testSingletonsAreFineAtFirst() { $sut = new SystemUnderTest; $sut->setData('foo'); //passes $this->assertEquals('foo', $sut->getData()); } public function testSingletonsNeverDie() { $sut = new SystemUnderTest; $actual = $sut->getData(); //fails $this->assertNull($actual); } }
  • 54. Many frameworks come with built in testing facilities, or the ability to easily integrate with PHPUnit.  Try to use the built-in testing tools. They usually do the heavy lifting of bootstrapping your application.
  • 55. Get your test harness working  Get your feet wet first, testing smaller/trivial code  Manual verification is prudent  Improve your design, refactor  Write tests for new code  Write tests opportunistically