testing untestable code - dpc10
TRANSCRIPT
![Page 1: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/1.jpg)
Testing untestable CodeStephan Hochdörfer, bitExpert AG
"Quality is a function of thought and reflection -
precise thought and reflection. That’s the magic."
Michael Feathers
![Page 2: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/2.jpg)
Agenda
1. About me
2. Theory
3. How to test untestable code
4. Generating testable code
5. Conclusions
6. Questions
![Page 3: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/3.jpg)
About me
Stephan Hochdörfer, bitExpert AG
Department Manager Research Labs
enjoying PHP since 1999
@shochdoerfer
![Page 4: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/4.jpg)
No excuse for bad code!
![Page 5: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/5.jpg)
Warning! Use at own risk...
![Page 6: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/6.jpg)
Theory
"There is no secret to writing tests, there
are only secrets to write testable code!"Miško Hevery
![Page 7: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/7.jpg)
Theory
What is „untestable code“?
![Page 8: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/8.jpg)
Theory
What is „untestable code“?
![Page 9: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/9.jpg)
Theory
What is „untestable code“?
![Page 10: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/10.jpg)
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
![Page 11: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/11.jpg)
Theory
Class toTest
Unittest
Requiredclass
Requiredclass
![Page 12: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/12.jpg)
Theory
Class totest
Unittest
Requiredclass
Requiredclass
Database
Externalresource
Requiredclass
Requiredclass
Webservice
![Page 13: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/13.jpg)
Theory
Class totest
Unittest
Requiredclass
Requiredclass
Database
Externalresource
Requiredclass
Requiredclass
Webservice
![Page 14: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/14.jpg)
Theory
How to achieve „testable“ code?
![Page 15: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/15.jpg)
Theory
How to achieve „testable“ code?
Refactoring
![Page 16: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/16.jpg)
Theory
"Before you start refactoring, check that you
have a solid suite of tests."Martin Fowler, Refactoring
![Page 17: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/17.jpg)
Testing „untestable“ PHP Code
Let the work begin...
![Page 18: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/18.jpg)
Testing „untestable“ PHP Code
For your safty!
Do not change existing code!
![Page 19: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/19.jpg)
Testing „untestable“ PHP Code | __autoload
<?phpclass Car {
private $Engine;
public function __construct($sEngine) {$this->Engine = Engine::getByType($sEngine);
}
}
![Page 20: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/20.jpg)
Testing „untestable“ PHP Code | __autoload
How to inject a dependency? Use __autoload
<?phpclass Car {
private $Engine;
public function __construct($sEngine) {$this->Engine = Engine::getByType($sEngine);
}
}
![Page 21: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/21.jpg)
Testing „untestable“ PHP Code | __autoload
<?phpfunction run_autoload($psClass) {
$sFileToInclude = strtolower($psClass).'.php';if(strtolower($psClass) == 'engine') {
$sFileToInclude = '/custom/mocks/'.$sFileToInclude;}include($sFileToInclude);
}
// Testcasespl_autoload_register('run_autoload');$oCar = new Car('Diesel');echo $oCar->run();
![Page 22: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/22.jpg)
Testing „untestable“ PHP Code | include_path
<?phpinclude('Engine.php');
class Car {private $Engine;
public function __construct($sEngine) {$this->Engine = Engine::getByType($sEngine);
}}
![Page 23: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/23.jpg)
Testing „untestable“ PHP Code | include_path
<?phpinclude('Engine.php');
class Car {private $Engine;
public function __construct($sEngine) {$this->Engine = Engine::getByType($sEngine);
}}
How to inject a dependency? Manipulate include_path setting
![Page 24: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/24.jpg)
Testing „untestable“ PHP Code | include_path
<?phpini_set('include_path',
'/custom/mocks/'.PATH_SEPARATOR.ini_get('include_path'));
// Testcaseinclude('car.php');
$oCar = new Car('Diesel');echo $oCar->run();
![Page 25: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/25.jpg)
Testing „untestable“ PHP Code | include_path alternative
<?phpclass 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
![Page 26: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/26.jpg)
Testing „untestable“ PHP Code | include_path alternative
<?phpclass 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');?>
![Page 27: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/27.jpg)
Testing „untestable“ PHP Code | Namespaces
<?phpclass Car {
private $Engine;
public function __construct($sEngine) {$this->Engine = Car\Engine::getByType($sEngine);
}}
![Page 28: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/28.jpg)
Testing „untestable“ PHP Code | Namespaces
<?phpclass Car {
private $Engine;
public function __construct($sEngine) {$this->Engine = Car\Engine::getByType($sEngine);
}}
How to inject a dependency? Use __autoload or manipulate the include_path
![Page 29: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/29.jpg)
Testing „untestable“ PHP Code | vfsStream
<?phpclass Car {
private $Engine;
public function __construct($sEngine, $CacheDir) {$this->Engine = Car\Engine::getByType($sEngine);mkdir($CacheDir.'/cache/', 0700, true);
}}
![Page 30: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/30.jpg)
Testing „untestable“ PHP Code | vfsStream
How mock a filesystem? Use vfsStream - http://code.google.com/p/bovigo/
<?phpclass Car {
private $Engine;
public function __construct($sEngine, $CacheDir) {$this->Engine = Car\Engine::getByType($sEngine);mkdir($CacheDir.'/cache/', 0700, true);
}}
![Page 31: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/31.jpg)
Testing „untestable“ PHP Code | vfsStream
<?php
// setup vfsStreamvfsStreamWrapper::register();vfsStreamWrapper::setRoot(new vfsStreamDirectory('app'));
$oCar = new Car('Diesel', vfsStream::url('app'));
echo vfsStreamWrapper::getRoot()->hasChild('cache');
![Page 32: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/32.jpg)
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
![Page 33: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/33.jpg)
Testing „untestable“ PHP Code | Test functions
<?phpfunction startsWith($sString, $psPre) {
return $psPre == substr($sString, 0, strlen($psPre));}
function contains($sString, $sSearch) {return false !== strpos($sString, $sSearch);
}
![Page 34: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/34.jpg)
Testing „untestable“ PHP Code | Test functions
How to test PHPUnit can call functions PHPUnit can save/restore globale state
<?phpfunction startsWith($sString, $psPre) {
return $psPre == substr($sString, 0, strlen($psPre));}
function contains($sString, $sSearch) {return false !== strpos($sString, $sSearch);
}
![Page 35: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/35.jpg)
Testing „untestable“ PHP Code | overwrite internal functions
<?phpfunction buyCar(Car $oCar) {
global $oDB;
mysql_query("INSERT INTO...", $oDB);
mail('[email protected]', 'New sale', '....');}
![Page 36: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/36.jpg)
Testing „untestable“ PHP Code | overwrite internal functions
<?phpfunction buyCar(Car $oCar) {
global $oDB;
mysql_query("INSERT INTO...", $oDB);
mail('[email protected]', 'New sale', '....');}
How to test Do not load mysql extension. Provide own implementation Unfortunatley mail() is part of the PHP core
![Page 37: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/37.jpg)
Testing „untestable“ PHP Code | overwrite internal functions
<?phpfunction buyCar(Car $oCar) {
global $oDB;
mysql_query("INSERT INTO...", $oDB);
mail('[email protected]', 'New sale', '....');}
How to test Use classkit extension to overwrite internal functions
![Page 38: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/38.jpg)
Testing „untestable“ PHP Code | overwrite internal functions
<?php
ini_set('runkit.internal_override', '1');
runkit_function_redefine('mail','','return true;');
?>
![Page 39: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/39.jpg)
Testing „untestable“ PHP Code
![Page 40: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/40.jpg)
Generative Programming
Generating testable code
![Page 41: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/41.jpg)
Generative Programming
Generating testable code
Configuration
Implementationcomponents
Generatorapplication
ProductGenerator
1 ... n
![Page 42: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/42.jpg)
Generative Programming
Generating testable code
Configuration
Implementationcomponents
Generatorapplication
Application
Generator
Testcases
![Page 43: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/43.jpg)
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
![Page 44: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/44.jpg)
Generating testable code
FileFrm FILEIndex_php5 { private String Prefix = "test_"; private String MailSlot = "mail('[email protected]', 'New sale', '....');";
public FILEIndex_php5() {setFilename("index.php5");setRelativePath("/");
}
private void assign() {BEGINCONTENT()<?phpfunction buyCar(Car $oCar) {global $oDB;
<!{Prefix}!>mysql_query(„INSERT INTO...“, $oDB);<!{MailSlot}!>}
?>ENDCONTENT() }}
![Page 45: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/45.jpg)
Generating testable code
<?phpfunction buyCar(Car $oCar) { global $oDB;
test_mysql_query("INSERT INTO...", $oDB);}
1. Example
Prefix: test_
![Page 46: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/46.jpg)
Generating testable code
<?phpfunction buyCar(Car $oCar) { global $oDB;
test_mysql_query("INSERT INTO...", $oDB);}
<?phpfunction buyCar(Car $oCar) { global $oDB;
mysql_query("INSERT INTO...", $oDB); mail('[email protected]', 'New sale', '....');}
?>
1. Example
Prefix: test_
2. Example
MailSlot: mail('[email protected]', 'New sale', '....');
![Page 47: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/47.jpg)
Conclusion
How much effort to take?
![Page 48: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/48.jpg)
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
![Page 49: Testing untestable code - DPC10](https://reader034.vdocuments.mx/reader034/viewer/2022052316/557cf96fd8b42a98158b4b89/html5/thumbnails/49.jpg)
http://joind.in/1545