SlideShare ist ein Scribd-Unternehmen logo
1 von 49
Downloaden Sie, um offline zu lesen
Testing untestable Code
   Stephan Hochdörfer, bitExpert AG




 "Quality is a function of thought and reflection -
 precise thought and reflection. That’s the magic."
                 Michael Feathers
Agenda
1.   About me

2.   Theory

3.   How to test untestable code

4.   Generating testable code

5.   Conclusions

6.   Questions
About me
 Stephan Hochdörfer, bitExpert AG

 Department Manager Research Labs

 enjoying PHP since 1999

 S.Hochdoerfer@bitExpert.de

 @shochdoerfer
No excuse for bad code!
Warning! Use at own risk...
Theory




         "There is no secret to writing tests, there
          are only secrets to write testable code!"
                         Miško Hevery
Theory



 What is „untestable code“?
Theory



 What is „untestable code“?
Theory



 What is „untestable code“?
Theory




          "...our test strategy requires us to have more control or
         visibility of the internal behavior of the system under test."
               Gerard Meszaros, xUnit Test Patterns: Refactoring Test Code
Theory




                               Required
                                class
                    Class to
         Unittest
                      Test
                               Required
                                class
Theory




                                          Database

                               Required
                                class
                                           External
                    Class to
         Unittest                          resource
                      test
                               Required
                                class




                    Required   Required
                                           Webservice
                     class      class
Theory




                                          Database

                               Required
                                class
                                           External
                    Class to
         Unittest                          resource
                      test
                               Required
                                class




                    Required   Required
                                           Webservice
                     class      class
Theory



 How to achieve „testable“ code?
Theory



 How to achieve „testable“ code?




                Refactoring
Theory




         "Before you start refactoring, check that you
                  have a solid suite of tests."
                     Martin Fowler, Refactoring
Testing „untestable“ PHP Code



 Let the work begin...
Testing „untestable“ PHP Code



 For your safty!




          Do not change existing code!
Testing „untestable“ PHP Code | __autoload




<?php
class Car {
    private $Engine;

     public function __construct($sEngine) {
         $this->Engine = Engine::getByType($sEngine);
     }

}
Testing „untestable“ PHP Code | __autoload




<?php
class Car {
    private $Engine;

     public function __construct($sEngine) {
         $this->Engine = Engine::getByType($sEngine);
     }

}




How to inject a dependency?
 Use __autoload
Testing „untestable“ PHP Code | __autoload




<?php
function run_autoload($psClass) {
    $sFileToInclude = strtolower($psClass).'.php';
    if(strtolower($psClass) == 'engine') {
         $sFileToInclude = '/custom/mocks/'.$sFileToInclude;
    }
    include($sFileToInclude);
}


// Testcase
spl_autoload_register('run_autoload');
$oCar = new Car('Diesel');
echo $oCar->run();
Testing „untestable“ PHP Code | include_path




<?php
include('Engine.php');

class Car {
    private $Engine;

     public function __construct($sEngine) {
         $this->Engine = Engine::getByType($sEngine);
     }
}
Testing „untestable“ PHP Code | include_path




<?php
include('Engine.php');

class Car {
    private $Engine;

     public function __construct($sEngine) {
         $this->Engine = Engine::getByType($sEngine);
     }
}




How to inject a dependency?
 Manipulate include_path setting
Testing „untestable“ PHP Code | include_path




<?php
ini_set('include_path',
    '/custom/mocks/'.PATH_SEPARATOR.
    ini_get('include_path'));

// Testcase
include('car.php');

$oCar = new Car('Diesel');
echo $oCar->run();
Testing „untestable“ PHP Code | include_path alternative

<?php
class CustomFileStreamWrapper {
  private $_handler;

    function stream_open($path, $mode, $options, &$opened_path) {
      stream_wrapper_restore('file');
       // @TODO: modify $path before fopen
      $this->_handler = fopen($path, $mode);
      stream_wrapper_unregister('file');
      stream_wrapper_register('file', 'CustomFileStreamWrapper');
      return true;
    }

    function stream_read($count) {}

    function stream_write($data) {}

    function stream_tell() {}

    function stream_eof() {}

    function stream_seek($offset, $whence) {}
}

stream_wrapper_unregister('file');
stream_wrapper_register('file', 'CustomFileStreamWrapper');



Source: Alex Netkachov, http://www.alexatnet.com/node/203
Testing „untestable“ PHP Code | include_path alternative

<?php
class CustomFileStreamWrapper {
      private $_handler;

       function stream_open($path, $mode, $options, &$opened_path) {
            stream_wrapper_restore('file');
            $this->_handler = fopen($path, $mode);
            stream_wrapper_unregister('file');
            stream_wrapper_register('file', 'CustomFileStreamWrapper');
            return true;
       }

       function stream_read($count) {
            $content = fread($this->_handler, $count);
            $content = str_replace('Engine::getByType', 'MockedEngine::get', $content);
            return $content;
       }
}

stream_wrapper_unregister('file');
stream_wrapper_register('file', 'CustomFileStreamWrapper');

include('engine.php');
?>
Testing „untestable“ PHP Code | Namespaces




<?php
class Car {
    private $Engine;

     public function __construct($sEngine) {
         $this->Engine = CarEngine::getByType($sEngine);
     }
}
Testing „untestable“ PHP Code | Namespaces




<?php
class Car {
    private $Engine;

     public function __construct($sEngine) {
         $this->Engine = CarEngine::getByType($sEngine);
     }
}




How to inject a dependency?
 Use __autoload or manipulate the include_path
Testing „untestable“ PHP Code | vfsStream




<?php
class Car {
    private $Engine;

     public function __construct($sEngine, $CacheDir) {
         $this->Engine = CarEngine::getByType($sEngine);
         mkdir($CacheDir.'/cache/', 0700, true);
     }
}
Testing „untestable“ PHP Code | vfsStream




<?php
class Car {
    private $Engine;

     public function __construct($sEngine, $CacheDir) {
         $this->Engine = CarEngine::getByType($sEngine);
         mkdir($CacheDir.'/cache/', 0700, true);
     }
}




How mock a filesystem?
 Use vfsStream - http://code.google.com/p/bovigo/
Testing „untestable“ PHP Code | vfsStream




<?php

// setup vfsStream
vfsStreamWrapper::register();
vfsStreamWrapper::setRoot(new vfsStreamDirectory('app'));

$oCar = new Car('Diesel', vfsStream::url('app'));

echo vfsStreamWrapper::getRoot()->hasChild('cache');
Testing „untestable“ PHP Code




       „I have no idea how to unit-test procedural code. Unit-testing
          assumes that I can instantiate a piece of my application in
                                  isolation.“
                                 Miško Hevery
Testing „untestable“ PHP Code | Test functions




<?php
function startsWith($sString, $psPre) {
    return $psPre == substr($sString, 0, strlen($psPre));
}

function contains($sString, $sSearch) {
    return false !== strpos($sString, $sSearch);
}
Testing „untestable“ PHP Code | Test functions




<?php
function startsWith($sString, $psPre) {
    return $psPre == substr($sString, 0, strlen($psPre));
}

function contains($sString, $sSearch) {
    return false !== strpos($sString, $sSearch);
}




How to test
 PHPUnit can call functions
 PHPUnit can save/restore globale state
Testing „untestable“ PHP Code | overwrite internal functions




<?php
function buyCar(Car $oCar) {
    global $oDB;

     mysql_query("INSERT INTO...", $oDB);

     mail('order@domain.org', 'New sale', '....');
}
Testing „untestable“ PHP Code | overwrite internal functions




<?php
function buyCar(Car $oCar) {
    global $oDB;

     mysql_query("INSERT INTO...", $oDB);

     mail('order@domain.org', 'New sale', '....');
}




How to test
 Do not load mysql extension. Provide own implementation
 Unfortunatley mail() is part of the PHP core
Testing „untestable“ PHP Code | overwrite internal functions




<?php
function buyCar(Car $oCar) {
    global $oDB;

     mysql_query("INSERT INTO...", $oDB);

     mail('order@domain.org', 'New sale', '....');
}




How to test
 Use classkit extension to overwrite internal functions
Testing „untestable“ PHP Code | overwrite internal functions




<?php

ini_set('runkit.internal_override', '1');

runkit_function_redefine('mail','','return true;');

?>
Testing „untestable“ PHP Code
Generating testable code



 Generative Programming
Generating testable code



 Generative Programming

                             Configuration




                                                         1 ... n
            Implementation
                                             Generator    Product
             components




                               Generator
                               application
Generating testable code



 Generative Programming

                             Configuration


                                                         Application



            Implementation
                                             Generator
             components



                                                         Testcases
                               Generator
                               application
Generating testable code



 Course of action
 Extraction
  „Mask“ parts of the code


 Customizing
  Change content of global vars
  Pre/Postfixes for own functions, methods, classes


 Recombine
  Re-order parts of the code
Generating testable code




FileFrm FILEIndex_php5 {
  private String Prefix   = "test_";
  private String MailSlot = "mail('order@domain.org', 'New sale', '....');";

   public FILEIndex_php5() {
     setFilename("index.php5");
     setRelativePath("/");
   }

  private void assign() {
BEGINCONTENT()
<?php
function buyCar(Car $oCar) {
global $oDB;

<!{Prefix}!>mysql_query(„INSERT INTO...“, $oDB);
<!{MailSlot}!>
}

?>
ENDCONTENT()
  }
}
Generating testable code




1. Example
Prefix: test_
<?php
function buyCar(Car $oCar) {
  global $oDB;

    test_mysql_query("INSERT INTO...", $oDB);
}
Generating testable code




1. Example
Prefix: test_
<?php
function buyCar(Car $oCar) {
  global $oDB;

     test_mysql_query("INSERT INTO...", $oDB);
}


2. Example
MailSlot: mail('order@domain.org', 'New sale', '....');
<?php
function buyCar(Car $oCar) {
  global $oDB;

     mysql_query("INSERT INTO...", $oDB);
     mail('order@domain.org', 'New sale', '....');
}

?>
Conclusion



 How much effort to take?
Conclusion



 Conclusion

  Change mindset to write testable code
        
          Dependency Injection

  Look for other options to raise the bar
         
           Work around limitations of PHP
         
           PHP is flexible, use it that way
http://joind.in/1545

Weitere ähnliche Inhalte

Was ist angesagt?

Real World Dependency Injection - PFCongres 2010
Real World Dependency Injection - PFCongres 2010Real World Dependency Injection - PFCongres 2010
Real World Dependency Injection - PFCongres 2010Stephan Hochdörfer
 
Real World Dependency Injection - IPC11 Spring Edition
Real World Dependency Injection - IPC11 Spring EditionReal World Dependency Injection - IPC11 Spring Edition
Real World Dependency Injection - IPC11 Spring EditionStephan Hochdörfer
 
Real World Dependency Injection SE - phpugrhh
Real World Dependency Injection SE - phpugrhhReal World Dependency Injection SE - phpugrhh
Real World Dependency Injection SE - phpugrhhStephan Hochdörfer
 
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...GeeksLab Odessa
 
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"GeeksLab Odessa
 
Testing untestable code - ConFoo13
Testing untestable code - ConFoo13Testing untestable code - ConFoo13
Testing untestable code - ConFoo13Stephan Hochdörfer
 
Developer testing 101: Become a Testing Fanatic
Developer testing 101: Become a Testing FanaticDeveloper testing 101: Become a Testing Fanatic
Developer testing 101: Become a Testing FanaticLB Denker
 
PHP 7 Crash Course
PHP 7 Crash CoursePHP 7 Crash Course
PHP 7 Crash CourseColin O'Dell
 
Invoke dynamite in Java EE with invoke dynamic
Invoke dynamite in Java EE with invoke dynamicInvoke dynamite in Java EE with invoke dynamic
Invoke dynamite in Java EE with invoke dynamicAntoine Sabot-Durand
 
Workshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublinWorkshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublinMichelangelo van Dam
 
Working Effectively With Legacy Code
Working Effectively With Legacy CodeWorking Effectively With Legacy Code
Working Effectively With Legacy Codescidept
 
Advanced java interview questions
Advanced java interview questionsAdvanced java interview questions
Advanced java interview questionsrithustutorials
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy CodeRowan Merewood
 
Serial Killer - Silently Pwning your Java Endpoints // OWASP BeNeLux Day 2016
Serial Killer - Silently Pwning your Java Endpoints // OWASP BeNeLux Day 2016Serial Killer - Silently Pwning your Java Endpoints // OWASP BeNeLux Day 2016
Serial Killer - Silently Pwning your Java Endpoints // OWASP BeNeLux Day 2016Christian Schneider
 

Was ist angesagt? (20)

Real World Dependency Injection - PFCongres 2010
Real World Dependency Injection - PFCongres 2010Real World Dependency Injection - PFCongres 2010
Real World Dependency Injection - PFCongres 2010
 
Real World Dependency Injection - IPC11 Spring Edition
Real World Dependency Injection - IPC11 Spring EditionReal World Dependency Injection - IPC11 Spring Edition
Real World Dependency Injection - IPC11 Spring Edition
 
Real World Dependency Injection SE - phpugrhh
Real World Dependency Injection SE - phpugrhhReal World Dependency Injection SE - phpugrhh
Real World Dependency Injection SE - phpugrhh
 
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
 
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
 
Testing untestable code - ConFoo13
Testing untestable code - ConFoo13Testing untestable code - ConFoo13
Testing untestable code - ConFoo13
 
Developer testing 101: Become a Testing Fanatic
Developer testing 101: Become a Testing FanaticDeveloper testing 101: Become a Testing Fanatic
Developer testing 101: Become a Testing Fanatic
 
PHP 7 Crash Course
PHP 7 Crash CoursePHP 7 Crash Course
PHP 7 Crash Course
 
Invoke dynamite in Java EE with invoke dynamic
Invoke dynamite in Java EE with invoke dynamicInvoke dynamite in Java EE with invoke dynamic
Invoke dynamite in Java EE with invoke dynamic
 
Invoke dynamics
Invoke dynamicsInvoke dynamics
Invoke dynamics
 
Workshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublinWorkshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublin
 
Working Effectively With Legacy Code
Working Effectively With Legacy CodeWorking Effectively With Legacy Code
Working Effectively With Legacy Code
 
Advanced java interview questions
Advanced java interview questionsAdvanced java interview questions
Advanced java interview questions
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy Code
 
Spring frame work
Spring frame workSpring frame work
Spring frame work
 
4.Spring IoC&DI(Spring Ioc실습_어노테이션 기반)
4.Spring IoC&DI(Spring Ioc실습_어노테이션 기반)4.Spring IoC&DI(Spring Ioc실습_어노테이션 기반)
4.Spring IoC&DI(Spring Ioc실습_어노테이션 기반)
 
Serial Killer - Silently Pwning your Java Endpoints // OWASP BeNeLux Day 2016
Serial Killer - Silently Pwning your Java Endpoints // OWASP BeNeLux Day 2016Serial Killer - Silently Pwning your Java Endpoints // OWASP BeNeLux Day 2016
Serial Killer - Silently Pwning your Java Endpoints // OWASP BeNeLux Day 2016
 
Laravel Unit Testing
Laravel Unit TestingLaravel Unit Testing
Laravel Unit Testing
 
Spring boot
Spring bootSpring boot
Spring boot
 
Javascript Best Practices
Javascript Best PracticesJavascript Best Practices
Javascript Best Practices
 

Ähnlich wie Testing untestable code - DPC10

Leveling Up With Unit Testing - LonghornPHP 2022
Leveling Up With Unit Testing - LonghornPHP 2022Leveling Up With Unit Testing - LonghornPHP 2022
Leveling Up With Unit Testing - LonghornPHP 2022Mark Niebergall
 
Leveling Up With Unit Testing - php[tek] 2023
Leveling Up With Unit Testing - php[tek] 2023Leveling Up With Unit Testing - php[tek] 2023
Leveling Up With Unit Testing - php[tek] 2023Mark Niebergall
 
Unit Testing from Setup to Deployment
Unit Testing from Setup to DeploymentUnit Testing from Setup to Deployment
Unit Testing from Setup to DeploymentMark Niebergall
 
Test Driven Development with PHPUnit
Test Driven Development with PHPUnitTest Driven Development with PHPUnit
Test Driven Development with PHPUnitMindfire Solutions
 
Better Testing With PHP Unit
Better Testing With PHP UnitBetter Testing With PHP Unit
Better Testing With PHP Unitsitecrafting
 
Test in action week 2
Test in action   week 2Test in action   week 2
Test in action week 2Yi-Huan Chan
 
2010 07-28-testing-zf-apps
2010 07-28-testing-zf-apps2010 07-28-testing-zf-apps
2010 07-28-testing-zf-appsVenkata Ramana
 
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
 
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
 
Test in action – week 1
Test in action – week 1Test in action – week 1
Test in action – week 1Yi-Huan Chan
 
Automated Unit Testing
Automated Unit TestingAutomated Unit Testing
Automated Unit TestingMike Lively
 
Working Effectively With Legacy Perl Code
Working Effectively With Legacy Perl CodeWorking Effectively With Legacy Perl Code
Working Effectively With Legacy Perl Codeerikmsp
 
What's new in PHP 8.0?
What's new in PHP 8.0?What's new in PHP 8.0?
What's new in PHP 8.0?Nikita Popov
 
Nikita Popov "What’s new in PHP 8.0?"
Nikita Popov "What’s new in PHP 8.0?"Nikita Popov "What’s new in PHP 8.0?"
Nikita Popov "What’s new in PHP 8.0?"Fwdays
 
EPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur PurnamaEPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur PurnamaEnterprise PHP Center
 
More on Fitnesse and Continuous Integration (Silicon Valley code camp 2012)
More on Fitnesse and Continuous Integration (Silicon Valley code camp 2012)More on Fitnesse and Continuous Integration (Silicon Valley code camp 2012)
More on Fitnesse and Continuous Integration (Silicon Valley code camp 2012)Jen Wong
 

Ähnlich wie Testing untestable code - DPC10 (20)

Leveling Up With Unit Testing - LonghornPHP 2022
Leveling Up With Unit Testing - LonghornPHP 2022Leveling Up With Unit Testing - LonghornPHP 2022
Leveling Up With Unit Testing - LonghornPHP 2022
 
Leveling Up With Unit Testing - php[tek] 2023
Leveling Up With Unit Testing - php[tek] 2023Leveling Up With Unit Testing - php[tek] 2023
Leveling Up With Unit Testing - php[tek] 2023
 
Unit Testing from Setup to Deployment
Unit Testing from Setup to DeploymentUnit Testing from Setup to Deployment
Unit Testing from Setup to Deployment
 
Test
TestTest
Test
 
Test Driven Development with PHPUnit
Test Driven Development with PHPUnitTest Driven Development with PHPUnit
Test Driven Development with PHPUnit
 
Testing untestable code - IPC12
Testing untestable code - IPC12Testing untestable code - IPC12
Testing untestable code - IPC12
 
Better Testing With PHP Unit
Better Testing With PHP UnitBetter Testing With PHP Unit
Better Testing With PHP Unit
 
Test in action week 2
Test in action   week 2Test in action   week 2
Test in action week 2
 
2010 07-28-testing-zf-apps
2010 07-28-testing-zf-apps2010 07-28-testing-zf-apps
2010 07-28-testing-zf-apps
 
Junit_.pptx
Junit_.pptxJunit_.pptx
Junit_.pptx
 
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
 
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
 
Test in action – week 1
Test in action – week 1Test in action – week 1
Test in action – week 1
 
Automated Unit Testing
Automated Unit TestingAutomated Unit Testing
Automated Unit Testing
 
Working Effectively With Legacy Perl Code
Working Effectively With Legacy Perl CodeWorking Effectively With Legacy Perl Code
Working Effectively With Legacy Perl Code
 
Good Practices On Test Automation
Good Practices On Test AutomationGood Practices On Test Automation
Good Practices On Test Automation
 
What's new in PHP 8.0?
What's new in PHP 8.0?What's new in PHP 8.0?
What's new in PHP 8.0?
 
Nikita Popov "What’s new in PHP 8.0?"
Nikita Popov "What’s new in PHP 8.0?"Nikita Popov "What’s new in PHP 8.0?"
Nikita Popov "What’s new in PHP 8.0?"
 
EPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur PurnamaEPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur Purnama
 
More on Fitnesse and Continuous Integration (Silicon Valley code camp 2012)
More on Fitnesse and Continuous Integration (Silicon Valley code camp 2012)More on Fitnesse and Continuous Integration (Silicon Valley code camp 2012)
More on Fitnesse and Continuous Integration (Silicon Valley code camp 2012)
 

Mehr von Stephan Hochdörfer

Offline. Na und? Strategien für offlinefähige Applikationen in HTML5 - Herbst...
Offline. Na und? Strategien für offlinefähige Applikationen in HTML5 - Herbst...Offline. Na und? Strategien für offlinefähige Applikationen in HTML5 - Herbst...
Offline. Na und? Strategien für offlinefähige Applikationen in HTML5 - Herbst...Stephan Hochdörfer
 
Phing for power users - frOSCon8
Phing for power users - frOSCon8Phing for power users - frOSCon8
Phing for power users - frOSCon8Stephan Hochdörfer
 
Offline strategies for HTML5 web applications - frOSCon8
Offline strategies for HTML5 web applications - frOSCon8Offline strategies for HTML5 web applications - frOSCon8
Offline strategies for HTML5 web applications - frOSCon8Stephan Hochdörfer
 
Offline Strategies for HTML5 Web Applications - oscon13
Offline Strategies for HTML5 Web Applications - oscon13Offline Strategies for HTML5 Web Applications - oscon13
Offline Strategies for HTML5 Web Applications - oscon13Stephan Hochdörfer
 
Real World Dependency Injection - oscon13
Real World Dependency Injection - oscon13Real World Dependency Injection - oscon13
Real World Dependency Injection - oscon13Stephan Hochdörfer
 
Dependency Injection in PHP - dwx13
Dependency Injection in PHP - dwx13Dependency Injection in PHP - dwx13
Dependency Injection in PHP - dwx13Stephan Hochdörfer
 
Offline Strategien für HTML5 Web Applikationen - dwx13
Offline Strategien für HTML5 Web Applikationen - dwx13 Offline Strategien für HTML5 Web Applikationen - dwx13
Offline Strategien für HTML5 Web Applikationen - dwx13 Stephan Hochdörfer
 
Your Business. Your Language. Your Code - dpc13
Your Business. Your Language. Your Code - dpc13Your Business. Your Language. Your Code - dpc13
Your Business. Your Language. Your Code - dpc13Stephan Hochdörfer
 
Phing for power users - dpc_uncon13
Phing for power users - dpc_uncon13Phing for power users - dpc_uncon13
Phing for power users - dpc_uncon13Stephan Hochdörfer
 
Offline Strategies for HTML5 Web Applications - ipc13
Offline Strategies for HTML5 Web Applications - ipc13Offline Strategies for HTML5 Web Applications - ipc13
Offline Strategies for HTML5 Web Applications - ipc13Stephan Hochdörfer
 
Offline-Strategien für HTML5 Web Applikationen - wmka
Offline-Strategien für HTML5 Web Applikationen - wmkaOffline-Strategien für HTML5 Web Applikationen - wmka
Offline-Strategien für HTML5 Web Applikationen - wmkaStephan Hochdörfer
 
Offline-Strategien für HTML5 Web Applikationen - bedcon13
Offline-Strategien für HTML5 Web Applikationen - bedcon13Offline-Strategien für HTML5 Web Applikationen - bedcon13
Offline-Strategien für HTML5 Web Applikationen - bedcon13Stephan Hochdörfer
 
Real World Dependency Injection - phpugffm13
Real World Dependency Injection - phpugffm13Real World Dependency Injection - phpugffm13
Real World Dependency Injection - phpugffm13Stephan Hochdörfer
 
Offline strategies for HTML5 web applications - ConFoo13
Offline strategies for HTML5 web applications - ConFoo13Offline strategies for HTML5 web applications - ConFoo13
Offline strategies for HTML5 web applications - ConFoo13Stephan Hochdörfer
 
Offline-Strategien für HTML5Web Applikationen - WMMRN12
Offline-Strategien für HTML5Web Applikationen - WMMRN12Offline-Strategien für HTML5Web Applikationen - WMMRN12
Offline-Strategien für HTML5Web Applikationen - WMMRN12Stephan Hochdörfer
 
Offline strategies for HTML5 web applications - IPC12
Offline strategies for HTML5 web applications - IPC12Offline strategies for HTML5 web applications - IPC12
Offline strategies for HTML5 web applications - IPC12Stephan Hochdörfer
 
Große Systeme, lose Kopplung, Spaß bei der Arbeit! - WDC12
Große Systeme, lose Kopplung, Spaß bei der Arbeit! - WDC12Große Systeme, lose Kopplung, Spaß bei der Arbeit! - WDC12
Große Systeme, lose Kopplung, Spaß bei der Arbeit! - WDC12Stephan Hochdörfer
 
Offline strategies for HTML5 web applications - pfCongres2012
Offline strategies for HTML5 web applications - pfCongres2012Offline strategies for HTML5 web applications - pfCongres2012
Offline strategies for HTML5 web applications - pfCongres2012Stephan Hochdörfer
 
Wie Software-Generatoren die Welt verändern können - Herbstcampus12
Wie Software-Generatoren die Welt verändern können - Herbstcampus12Wie Software-Generatoren die Welt verändern können - Herbstcampus12
Wie Software-Generatoren die Welt verändern können - Herbstcampus12Stephan Hochdörfer
 

Mehr von Stephan Hochdörfer (20)

Offline. Na und? Strategien für offlinefähige Applikationen in HTML5 - Herbst...
Offline. Na und? Strategien für offlinefähige Applikationen in HTML5 - Herbst...Offline. Na und? Strategien für offlinefähige Applikationen in HTML5 - Herbst...
Offline. Na und? Strategien für offlinefähige Applikationen in HTML5 - Herbst...
 
Phing for power users - frOSCon8
Phing for power users - frOSCon8Phing for power users - frOSCon8
Phing for power users - frOSCon8
 
Offline strategies for HTML5 web applications - frOSCon8
Offline strategies for HTML5 web applications - frOSCon8Offline strategies for HTML5 web applications - frOSCon8
Offline strategies for HTML5 web applications - frOSCon8
 
Offline Strategies for HTML5 Web Applications - oscon13
Offline Strategies for HTML5 Web Applications - oscon13Offline Strategies for HTML5 Web Applications - oscon13
Offline Strategies for HTML5 Web Applications - oscon13
 
Real World Dependency Injection - oscon13
Real World Dependency Injection - oscon13Real World Dependency Injection - oscon13
Real World Dependency Injection - oscon13
 
Dependency Injection in PHP - dwx13
Dependency Injection in PHP - dwx13Dependency Injection in PHP - dwx13
Dependency Injection in PHP - dwx13
 
Offline Strategien für HTML5 Web Applikationen - dwx13
Offline Strategien für HTML5 Web Applikationen - dwx13 Offline Strategien für HTML5 Web Applikationen - dwx13
Offline Strategien für HTML5 Web Applikationen - dwx13
 
Your Business. Your Language. Your Code - dpc13
Your Business. Your Language. Your Code - dpc13Your Business. Your Language. Your Code - dpc13
Your Business. Your Language. Your Code - dpc13
 
Phing for power users - dpc_uncon13
Phing for power users - dpc_uncon13Phing for power users - dpc_uncon13
Phing for power users - dpc_uncon13
 
Offline Strategies for HTML5 Web Applications - ipc13
Offline Strategies for HTML5 Web Applications - ipc13Offline Strategies for HTML5 Web Applications - ipc13
Offline Strategies for HTML5 Web Applications - ipc13
 
Offline-Strategien für HTML5 Web Applikationen - wmka
Offline-Strategien für HTML5 Web Applikationen - wmkaOffline-Strategien für HTML5 Web Applikationen - wmka
Offline-Strategien für HTML5 Web Applikationen - wmka
 
Offline-Strategien für HTML5 Web Applikationen - bedcon13
Offline-Strategien für HTML5 Web Applikationen - bedcon13Offline-Strategien für HTML5 Web Applikationen - bedcon13
Offline-Strategien für HTML5 Web Applikationen - bedcon13
 
Real World Dependency Injection - phpugffm13
Real World Dependency Injection - phpugffm13Real World Dependency Injection - phpugffm13
Real World Dependency Injection - phpugffm13
 
A Phing fairy tale - ConFoo13
A Phing fairy tale - ConFoo13A Phing fairy tale - ConFoo13
A Phing fairy tale - ConFoo13
 
Offline strategies for HTML5 web applications - ConFoo13
Offline strategies for HTML5 web applications - ConFoo13Offline strategies for HTML5 web applications - ConFoo13
Offline strategies for HTML5 web applications - ConFoo13
 
Offline-Strategien für HTML5Web Applikationen - WMMRN12
Offline-Strategien für HTML5Web Applikationen - WMMRN12Offline-Strategien für HTML5Web Applikationen - WMMRN12
Offline-Strategien für HTML5Web Applikationen - WMMRN12
 
Offline strategies for HTML5 web applications - IPC12
Offline strategies for HTML5 web applications - IPC12Offline strategies for HTML5 web applications - IPC12
Offline strategies for HTML5 web applications - IPC12
 
Große Systeme, lose Kopplung, Spaß bei der Arbeit! - WDC12
Große Systeme, lose Kopplung, Spaß bei der Arbeit! - WDC12Große Systeme, lose Kopplung, Spaß bei der Arbeit! - WDC12
Große Systeme, lose Kopplung, Spaß bei der Arbeit! - WDC12
 
Offline strategies for HTML5 web applications - pfCongres2012
Offline strategies for HTML5 web applications - pfCongres2012Offline strategies for HTML5 web applications - pfCongres2012
Offline strategies for HTML5 web applications - pfCongres2012
 
Wie Software-Generatoren die Welt verändern können - Herbstcampus12
Wie Software-Generatoren die Welt verändern können - Herbstcampus12Wie Software-Generatoren die Welt verändern können - Herbstcampus12
Wie Software-Generatoren die Welt verändern können - Herbstcampus12
 

Kürzlich hochgeladen

Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningLars Bell
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfPrecisely
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 

Kürzlich hochgeladen (20)

Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine Tuning
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 

Testing untestable code - DPC10

  • 1. Testing untestable Code Stephan Hochdörfer, bitExpert AG "Quality is a function of thought and reflection - precise thought and reflection. That’s the magic." Michael Feathers
  • 2. Agenda 1. About me 2. Theory 3. How to test untestable code 4. Generating testable code 5. Conclusions 6. Questions
  • 3. About me  Stephan Hochdörfer, bitExpert AG  Department Manager Research Labs  enjoying PHP since 1999  S.Hochdoerfer@bitExpert.de  @shochdoerfer
  • 4. No excuse for bad code!
  • 5. Warning! Use at own risk...
  • 6. Theory "There is no secret to writing tests, there are only secrets to write testable code!" Miško Hevery
  • 7. Theory What is „untestable code“?
  • 8. Theory What is „untestable code“?
  • 9. Theory What is „untestable code“?
  • 10. Theory "...our test strategy requires us to have more control or visibility of the internal behavior of the system under test." Gerard Meszaros, xUnit Test Patterns: Refactoring Test Code
  • 11. Theory Required class Class to Unittest Test Required class
  • 12. Theory Database Required class External Class to Unittest resource test Required class Required Required Webservice class class
  • 13. Theory Database Required class External Class to Unittest resource test Required class Required Required Webservice class class
  • 14. Theory How to achieve „testable“ code?
  • 15. Theory How to achieve „testable“ code? Refactoring
  • 16. Theory "Before you start refactoring, check that you have a solid suite of tests." Martin Fowler, Refactoring
  • 17. Testing „untestable“ PHP Code Let the work begin...
  • 18. Testing „untestable“ PHP Code For your safty! Do not change existing code!
  • 19. Testing „untestable“ PHP Code | __autoload <?php class Car { private $Engine; public function __construct($sEngine) { $this->Engine = Engine::getByType($sEngine); } }
  • 20. Testing „untestable“ PHP Code | __autoload <?php class Car { private $Engine; public function __construct($sEngine) { $this->Engine = Engine::getByType($sEngine); } } How to inject a dependency?  Use __autoload
  • 21. Testing „untestable“ PHP Code | __autoload <?php function run_autoload($psClass) { $sFileToInclude = strtolower($psClass).'.php'; if(strtolower($psClass) == 'engine') { $sFileToInclude = '/custom/mocks/'.$sFileToInclude; } include($sFileToInclude); } // Testcase spl_autoload_register('run_autoload'); $oCar = new Car('Diesel'); echo $oCar->run();
  • 22. Testing „untestable“ PHP Code | include_path <?php include('Engine.php'); class Car { private $Engine; public function __construct($sEngine) { $this->Engine = Engine::getByType($sEngine); } }
  • 23. Testing „untestable“ PHP Code | include_path <?php include('Engine.php'); class Car { private $Engine; public function __construct($sEngine) { $this->Engine = Engine::getByType($sEngine); } } How to inject a dependency?  Manipulate include_path setting
  • 24. Testing „untestable“ PHP Code | include_path <?php ini_set('include_path', '/custom/mocks/'.PATH_SEPARATOR. ini_get('include_path')); // Testcase include('car.php'); $oCar = new Car('Diesel'); echo $oCar->run();
  • 25. Testing „untestable“ PHP Code | include_path alternative <?php class CustomFileStreamWrapper { private $_handler; function stream_open($path, $mode, $options, &$opened_path) { stream_wrapper_restore('file'); // @TODO: modify $path before fopen $this->_handler = fopen($path, $mode); stream_wrapper_unregister('file'); stream_wrapper_register('file', 'CustomFileStreamWrapper'); return true; } function stream_read($count) {} function stream_write($data) {} function stream_tell() {} function stream_eof() {} function stream_seek($offset, $whence) {} } stream_wrapper_unregister('file'); stream_wrapper_register('file', 'CustomFileStreamWrapper'); Source: Alex Netkachov, http://www.alexatnet.com/node/203
  • 26. Testing „untestable“ PHP Code | include_path alternative <?php class CustomFileStreamWrapper { private $_handler; function stream_open($path, $mode, $options, &$opened_path) { stream_wrapper_restore('file'); $this->_handler = fopen($path, $mode); stream_wrapper_unregister('file'); stream_wrapper_register('file', 'CustomFileStreamWrapper'); return true; } function stream_read($count) { $content = fread($this->_handler, $count); $content = str_replace('Engine::getByType', 'MockedEngine::get', $content); return $content; } } stream_wrapper_unregister('file'); stream_wrapper_register('file', 'CustomFileStreamWrapper'); include('engine.php'); ?>
  • 27. Testing „untestable“ PHP Code | Namespaces <?php class Car { private $Engine; public function __construct($sEngine) { $this->Engine = CarEngine::getByType($sEngine); } }
  • 28. Testing „untestable“ PHP Code | Namespaces <?php class Car { private $Engine; public function __construct($sEngine) { $this->Engine = CarEngine::getByType($sEngine); } } How to inject a dependency?  Use __autoload or manipulate the include_path
  • 29. Testing „untestable“ PHP Code | vfsStream <?php class Car { private $Engine; public function __construct($sEngine, $CacheDir) { $this->Engine = CarEngine::getByType($sEngine); mkdir($CacheDir.'/cache/', 0700, true); } }
  • 30. Testing „untestable“ PHP Code | vfsStream <?php class Car { private $Engine; public function __construct($sEngine, $CacheDir) { $this->Engine = CarEngine::getByType($sEngine); mkdir($CacheDir.'/cache/', 0700, true); } } How mock a filesystem?  Use vfsStream - http://code.google.com/p/bovigo/
  • 31. Testing „untestable“ PHP Code | vfsStream <?php // setup vfsStream vfsStreamWrapper::register(); vfsStreamWrapper::setRoot(new vfsStreamDirectory('app')); $oCar = new Car('Diesel', vfsStream::url('app')); echo vfsStreamWrapper::getRoot()->hasChild('cache');
  • 32. Testing „untestable“ PHP Code „I have no idea how to unit-test procedural code. Unit-testing assumes that I can instantiate a piece of my application in isolation.“ Miško Hevery
  • 33. Testing „untestable“ PHP Code | Test functions <?php function startsWith($sString, $psPre) { return $psPre == substr($sString, 0, strlen($psPre)); } function contains($sString, $sSearch) { return false !== strpos($sString, $sSearch); }
  • 34. Testing „untestable“ PHP Code | Test functions <?php function startsWith($sString, $psPre) { return $psPre == substr($sString, 0, strlen($psPre)); } function contains($sString, $sSearch) { return false !== strpos($sString, $sSearch); } How to test  PHPUnit can call functions  PHPUnit can save/restore globale state
  • 35. Testing „untestable“ PHP Code | overwrite internal functions <?php function buyCar(Car $oCar) { global $oDB; mysql_query("INSERT INTO...", $oDB); mail('order@domain.org', 'New sale', '....'); }
  • 36. Testing „untestable“ PHP Code | overwrite internal functions <?php function buyCar(Car $oCar) { global $oDB; mysql_query("INSERT INTO...", $oDB); mail('order@domain.org', 'New sale', '....'); } How to test  Do not load mysql extension. Provide own implementation  Unfortunatley mail() is part of the PHP core
  • 37. Testing „untestable“ PHP Code | overwrite internal functions <?php function buyCar(Car $oCar) { global $oDB; mysql_query("INSERT INTO...", $oDB); mail('order@domain.org', 'New sale', '....'); } How to test  Use classkit extension to overwrite internal functions
  • 38. Testing „untestable“ PHP Code | overwrite internal functions <?php ini_set('runkit.internal_override', '1'); runkit_function_redefine('mail','','return true;'); ?>
  • 40. Generating testable code Generative Programming
  • 41. Generating testable code Generative Programming Configuration 1 ... n Implementation Generator Product components Generator application
  • 42. Generating testable code Generative Programming Configuration Application Implementation Generator components Testcases Generator application
  • 43. Generating testable code Course of action Extraction  „Mask“ parts of the code Customizing  Change content of global vars  Pre/Postfixes for own functions, methods, classes Recombine  Re-order parts of the code
  • 44. Generating testable code FileFrm FILEIndex_php5 { private String Prefix = "test_"; private String MailSlot = "mail('order@domain.org', 'New sale', '....');"; public FILEIndex_php5() { setFilename("index.php5"); setRelativePath("/"); } private void assign() { BEGINCONTENT() <?php function buyCar(Car $oCar) { global $oDB; <!{Prefix}!>mysql_query(„INSERT INTO...“, $oDB); <!{MailSlot}!> } ?> ENDCONTENT() } }
  • 45. Generating testable code 1. Example Prefix: test_ <?php function buyCar(Car $oCar) { global $oDB; test_mysql_query("INSERT INTO...", $oDB); }
  • 46. Generating testable code 1. Example Prefix: test_ <?php function buyCar(Car $oCar) { global $oDB; test_mysql_query("INSERT INTO...", $oDB); } 2. Example MailSlot: mail('order@domain.org', 'New sale', '....'); <?php function buyCar(Car $oCar) { global $oDB; mysql_query("INSERT INTO...", $oDB); mail('order@domain.org', 'New sale', '....'); } ?>
  • 47. Conclusion How much effort to take?
  • 48. Conclusion Conclusion  Change mindset to write testable code  Dependency Injection  Look for other options to raise the bar  Work around limitations of PHP  PHP is flexible, use it that way