SlideShare a Scribd company logo
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
About me
 Founder of bitExpert AG, Mannheim

 Field of duty
         
           Department Manager of Research Labs
         
           Head of Development for bitFramework

 Focusing on
        
          PHP
        
          Generative Programming


    Contact me
          
            @shochdoerfer
          
            S.Hochdoerfer@bitExpert.de
Agenda
1.   Theory

2.   How to test untestable PHP Code

3.   Generate testable code

4.   Conclusion
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“?

  Global variables
          
            Singleton
          
            Registry
          
            Globale state
  static method calls
  Control flow in a constructor
  Tight coupling
          
            Dependencies to concrete implementations
          
            to many dependencies to other classes
          
            Dependencies without control
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
Agenda
1.   Theory

2.   Testing untestable PHP Code

3.   Generate testable code

4.   Conclusion
Agenda
1.   Theory

2.   Testing untestable PHP Code
     – Hardcoded Dependencies
     – Procedural code
     – Overwrite internal PHP functions

3.   Generate testable code

4.   Conclusion
Testing „untestable“ PHP Code



 Assumption




          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 | 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');
Agenda
1.   Theory

2.   Testing untestable PHP Code
     – Hardcoded Dependencies
     – Procedural code
     – Overwrite internal PHP functions

3.   Generate testable code

4.   Conclusion
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 methods
 PHPUnit can save/restore globale state
Agenda
1.   Theory

2.   Testing untestable PHP Code
     – Hardcoded Dependencies
     – Procedural code
     – Overwrite internal PHP functions

3.   Generate testable code

4.   Conclusion
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
 Unfortunatly 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 mock internal functions
Testing „untestable“ PHP Code | overwrite internal functions




<?php

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

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

?>
Agenda
1.   Theory

2.   Testing untestable PHP Code

3.   Generate testable code

4.   Conclusion
Generate testable code



 Generative Programming

                             Configuration




                                                         1 ... n
            Implementation
                                             Generator    Product
             components




                               Generator
                               application
Generate testable code



 Generative Programming

                             Configuration


                                                         Application



            Implementation
                                             Generator
             components



                                                         Testcases
                               Generator
                               application
Generate 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
Generate 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()
  }
}
Generate testable code




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

    test_mysql_query("INSERT INTO...", $oDB);
}
Generate 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', '....');
}

?>
Conclustion



 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
Testing untestable Code - PFCongres 2010

More Related Content

PDF
Testing untestable code - DPC10
PDF
Real world dependency injection - DPC10
PDF
Real World Dependency Injection - oscon13
PDF
Offline Strategies for HTML5 Web Applications - oscon13
PDF
Offline strategies for HTML5 web applications - frOSCon8
PDF
Phing for power users - dpc_uncon13
PDF
Phing for power users - frOSCon8
PDF
Dependency Injection in PHP - dwx13
Testing untestable code - DPC10
Real world dependency injection - DPC10
Real World Dependency Injection - oscon13
Offline Strategies for HTML5 Web Applications - oscon13
Offline strategies for HTML5 web applications - frOSCon8
Phing for power users - dpc_uncon13
Phing for power users - frOSCon8
Dependency Injection in PHP - dwx13

What's hot (20)

PDF
Real World Dependency Injection - phpugffm13
PDF
Real World Dependency Injection - IPC11 Spring Edition
PPTX
Thinking Beyond ORM in JPA
PDF
Offline Strategies for HTML5 Web Applications - ipc13
PDF
Your Business. Your Language. Your Code - dpc13
PDF
Testing untestable code - phpday
PDF
Offline strategies for HTML5 web applications - IPC12
PDF
GDG Addis - An Introduction to Django and App Engine
PDF
Real World Dependency Injection - phpday
PDF
Invoke dynamite in Java EE with invoke dynamic
PDF
Extracting Plugins And Gems From Rails Apps
PDF
Easy tests with Selenide and Easyb
PDF
Real World Dependency Injection SE - phpugrhh
PDF
Javascript Best Practices
PDF
Workshop quality assurance for php projects - phpdublin
PDF
Node.js vs Play Framework (with Japanese subtitles)
PDF
Spring AOP
PDF
JavaScript Library Overview
PDF
Metrics-Driven Engineering
PDF
vJUG - The JavaFX Ecosystem
Real World Dependency Injection - phpugffm13
Real World Dependency Injection - IPC11 Spring Edition
Thinking Beyond ORM in JPA
Offline Strategies for HTML5 Web Applications - ipc13
Your Business. Your Language. Your Code - dpc13
Testing untestable code - phpday
Offline strategies for HTML5 web applications - IPC12
GDG Addis - An Introduction to Django and App Engine
Real World Dependency Injection - phpday
Invoke dynamite in Java EE with invoke dynamic
Extracting Plugins And Gems From Rails Apps
Easy tests with Selenide and Easyb
Real World Dependency Injection SE - phpugrhh
Javascript Best Practices
Workshop quality assurance for php projects - phpdublin
Node.js vs Play Framework (with Japanese subtitles)
Spring AOP
JavaScript Library Overview
Metrics-Driven Engineering
vJUG - The JavaFX Ecosystem
Ad

Similar to Testing untestable Code - PFCongres 2010 (20)

PDF
Testing untestable code - PHPBNL11
PDF
Testing untestable code - phpconpl11
PDF
Testing untestable code - STPCon11
PDF
Leveling Up With Unit Testing - php[tek] 2023
PDF
Leveling Up With Unit Testing - LonghornPHP 2022
KEY
Developer testing 101: Become a Testing Fanatic
PDF
Testing untestable code - IPC12
PDF
Testing untestable code - oscon 2012
PDF
Testing untestable code - ConFoo13
ZIP
Test
PDF
Unit Testing from Setup to Deployment
PPT
Test Driven Development with PHPUnit
PDF
Better Testing With PHP Unit
PDF
Working Effectively With Legacy Perl Code
PPTX
Test in action – week 1
KEY
Workshop quality assurance for php projects tek12
PDF
Quality Assurance for PHP projects - ZendCon 2012
PDF
2010 07-28-testing-zf-apps
ODP
New Ideas for Old Code - Greach
PPT
Selenium-Webdriver With PHPUnit Automation test for Joomla CMS!
Testing untestable code - PHPBNL11
Testing untestable code - phpconpl11
Testing untestable code - STPCon11
Leveling Up With Unit Testing - php[tek] 2023
Leveling Up With Unit Testing - LonghornPHP 2022
Developer testing 101: Become a Testing Fanatic
Testing untestable code - IPC12
Testing untestable code - oscon 2012
Testing untestable code - ConFoo13
Test
Unit Testing from Setup to Deployment
Test Driven Development with PHPUnit
Better Testing With PHP Unit
Working Effectively With Legacy Perl Code
Test in action – week 1
Workshop quality assurance for php projects tek12
Quality Assurance for PHP projects - ZendCon 2012
2010 07-28-testing-zf-apps
New Ideas for Old Code - Greach
Selenium-Webdriver With PHPUnit Automation test for Joomla CMS!
Ad

More from Stephan Hochdörfer (16)

PDF
Offline. Na und? Strategien für offlinefähige Applikationen in HTML5 - Herbst...
PDF
Offline Strategien für HTML5 Web Applikationen - dwx13
PDF
Offline-Strategien für HTML5 Web Applikationen - wmka
PDF
Offline-Strategien für HTML5 Web Applikationen - bedcon13
PDF
A Phing fairy tale - ConFoo13
PDF
Offline strategies for HTML5 web applications - ConFoo13
PDF
Offline-Strategien für HTML5Web Applikationen - WMMRN12
PDF
Große Systeme, lose Kopplung, Spaß bei der Arbeit! - WDC12
PDF
Offline strategies for HTML5 web applications - pfCongres2012
PDF
Wie Software-Generatoren die Welt verändern können - Herbstcampus12
PDF
Testing untestable code - Herbstcampus12
PDF
Introducing a Software Generator Framework - JAZOON12
PDF
The state of DI - DPC12
PDF
Separation of concerns - DPC12
PDF
Managing variability in software applications - scandev12
PDF
The state of DI in PHP - phpbnl12
Offline. Na und? Strategien für offlinefähige Applikationen in HTML5 - Herbst...
Offline Strategien für HTML5 Web Applikationen - dwx13
Offline-Strategien für HTML5 Web Applikationen - wmka
Offline-Strategien für HTML5 Web Applikationen - bedcon13
A Phing fairy tale - ConFoo13
Offline strategies for HTML5 web applications - ConFoo13
Offline-Strategien für HTML5Web Applikationen - WMMRN12
Große Systeme, lose Kopplung, Spaß bei der Arbeit! - WDC12
Offline strategies for HTML5 web applications - pfCongres2012
Wie Software-Generatoren die Welt verändern können - Herbstcampus12
Testing untestable code - Herbstcampus12
Introducing a Software Generator Framework - JAZOON12
The state of DI - DPC12
Separation of concerns - DPC12
Managing variability in software applications - scandev12
The state of DI in PHP - phpbnl12

Recently uploaded (20)

PDF
MIND Revenue Release Quarter 2 2025 Press Release
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PPTX
Cloud computing and distributed systems.
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
cuic standard and advanced reporting.pdf
PPTX
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PDF
Encapsulation_ Review paper, used for researhc scholars
PDF
Electronic commerce courselecture one. Pdf
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PPTX
Spectroscopy.pptx food analysis technology
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
MIND Revenue Release Quarter 2 2025 Press Release
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Cloud computing and distributed systems.
“AI and Expert System Decision Support & Business Intelligence Systems”
Spectral efficient network and resource selection model in 5G networks
cuic standard and advanced reporting.pdf
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
Encapsulation_ Review paper, used for researhc scholars
Electronic commerce courselecture one. Pdf
Per capita expenditure prediction using model stacking based on satellite ima...
Mobile App Security Testing_ A Comprehensive Guide.pdf
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
Spectroscopy.pptx food analysis technology
Agricultural_Statistics_at_a_Glance_2022_0.pdf
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy

Testing untestable Code - PFCongres 2010

  • 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. About me  Founder of bitExpert AG, Mannheim  Field of duty  Department Manager of Research Labs  Head of Development for bitFramework  Focusing on  PHP  Generative Programming  Contact me  @shochdoerfer  S.Hochdoerfer@bitExpert.de
  • 3. Agenda 1. Theory 2. How to test untestable PHP Code 3. Generate testable code 4. Conclusion
  • 4. Theory "There is no secret to writing tests, there are only secrets to write testable code!" Miško Hevery
  • 5. Theory What is „untestable code“?
  • 6. Theory What is „untestable code“?  Global variables  Singleton  Registry  Globale state  static method calls  Control flow in a constructor  Tight coupling  Dependencies to concrete implementations  to many dependencies to other classes  Dependencies without control
  • 7. 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
  • 8. Theory Required class Class to Unittest Test Required class
  • 9. Theory Database Required class External Class to Unittest resource test Required class Required Required Webservice class class
  • 10. Theory Database Required class External Class to Unittest resource test Required class Required Required Webservice class class
  • 11. Theory How to achieve „testable“ code?
  • 12. Theory How to achieve „testable“ code? Refactoring
  • 13. Theory "Before you start refactoring, check that you have a solid suite of tests." Martin Fowler, Refactoring
  • 14. Agenda 1. Theory 2. Testing untestable PHP Code 3. Generate testable code 4. Conclusion
  • 15. Agenda 1. Theory 2. Testing untestable PHP Code – Hardcoded Dependencies – Procedural code – Overwrite internal PHP functions 3. Generate testable code 4. Conclusion
  • 16. Testing „untestable“ PHP Code Assumption Do not change existing code!
  • 17. Testing „untestable“ PHP Code | __autoload <?php class Car { private $Engine; public function __construct($sEngine) { $this->Engine = Engine::getByType($sEngine); } }
  • 18. 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
  • 19. 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();
  • 20. Testing „untestable“ PHP Code | include_path <?php include('Engine.php'); class Car { private $Engine; public function __construct($sEngine) { $this->Engine = Engine::getByType($sEngine); } }
  • 21. 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
  • 22. 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();
  • 23. 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
  • 24. Testing „untestable“ PHP Code | Namespaces <?php class Car { private $Engine; public function __construct($sEngine) { $this->Engine = CarEngine::getByType($sEngine); } }
  • 25. 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
  • 26. 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); } }
  • 27. 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/
  • 28. 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');
  • 29. Agenda 1. Theory 2. Testing untestable PHP Code – Hardcoded Dependencies – Procedural code – Overwrite internal PHP functions 3. Generate testable code 4. Conclusion
  • 30. 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
  • 31. 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); }
  • 32. 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 methods  PHPUnit can save/restore globale state
  • 33. Agenda 1. Theory 2. Testing untestable PHP Code – Hardcoded Dependencies – Procedural code – Overwrite internal PHP functions 3. Generate testable code 4. Conclusion
  • 34. 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', '....'); }
  • 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', '....'); } How to test  Do not load mysql extension. Provide own implementation  Unfortunatly mail() is part of the PHP core
  • 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  Use classkit extension to mock internal functions
  • 37. Testing „untestable“ PHP Code | overwrite internal functions <?php ini_set('runkit.internal_override', '1'); runkit_function_redefine('mail','','return true;'); ?>
  • 38. Agenda 1. Theory 2. Testing untestable PHP Code 3. Generate testable code 4. Conclusion
  • 39. Generate testable code Generative Programming Configuration 1 ... n Implementation Generator Product components Generator application
  • 40. Generate testable code Generative Programming Configuration Application Implementation Generator components Testcases Generator application
  • 41. Generate 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
  • 42. Generate 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() } }
  • 43. Generate testable code 1. Example Prefix: test_ <?php function buyCar(Car $oCar) { global $oDB; test_mysql_query("INSERT INTO...", $oDB); }
  • 44. Generate 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', '....'); } ?>
  • 45. Conclustion 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