2. Testing untestable code
About me
ď§ Stephan HochdĂśrfer
ď§ Head of IT at bitExpert AG, Germany
ď§ enjoying PHP since 1999
ď§ S.Hochdoerfer@bitExpert.de
ď§ @shochdoerfer
14. Testing untestable code
"...our test strategy requires us to
have more control [...] of the sut."
Gerard Meszaros, xUnit Test Patterns: Refactoring Test
Code
30. Testing untestable code
Object construction â Stream Wrapper
<?php
class CustomWrapper {
  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', 'CustomWrapper');
    return true;
  }
}
32. Testing untestable code
Object construction â Stream Wrapper
<?php
class CustomWrapper {
private $_handler;
function stream_read($count) {
$content = fread($thisÂ>_handler, $count);
$content = str_replace('Engine::getByType',
       'AbstractEngine::get', $content);
return $content;
}
}
39. Testing untestable code
External resources â Mock database
require_onceÂ
"PHPUnit/Extensions/Database/TestCase.php";
class MySampleTest extendsÂ
PHPUnit_Extensions_Database_TestCase
{
    public function getConnection() {
        $pdo = new PDO('sqlite::memory:');
        return $thisÂ>createDefaultDBConnection
        $pdo, ':memory:');
    }
    public function getDataSet() {
        return $thisÂ>createFlatXMLDataSet(
        dirname(__FILE__).'/_files/data.xml'
    );
    }
}
51. Testing untestable code
Dealing with language issues
<?php
class CustomWrapper {
private $_handler;
function stream_read($count) {
$content = fread($thisÂ>_handler, $count);
$content = str_replace(
         'private function',
         'public function',Â
         $content
      );
return $content;
}
}
52. Testing untestable code
Dealing with language issues
$myClass = new MyClass();
$reflectionClass  = new ReflectionClass('MyClass');
$reflectionMethod = $reflectionClassÂ>
getMethod('mydemo');
$reflectionMethodÂ>setAccessible(true);
$reflectionMethodÂ>invoke($myClass);
57. Testing untestable code
Dealing with language issues - Funcall
<?php
function my_func($arg1, $arg2) {
    return $arg1.$arg2;
}
function post_cb($args,$result,
$process_time)Â {
  // return custom result based onÂ
$args
}
fc_add_post('my_func','post_cb');
var_dump(my_func('php', 'c'));
60. Testing untestable code
Dealing with language issues - AOP
<?php
aop_add_after('Car::drive*',Â
'adviceForDrive');
61. Testing untestable code
Dealing with language issues - AOP
<?php
$advice = function(AopTriggeredJoinpoint
$jp)Â {
  $returnValue =Â
     $jpÂ>getReturnedValue();
  // modify the return value
  $returnValue = 1234;
  $jpÂ>setReturnedValue($returnValue);
};
aop_add_after('CarÂ>drive()', $advice);
62. Testing untestable code
And now? Spaghetti mess...
<?php
$all_tables_query  = ' SELECT table_name, MAX(version) as
version FROM ...';
$all_tables_result =Â
PMA_query_as_controluser($all_tables_query);
// If a HEAD version exists
if (PMA_DBI_num_rows($all_tables_result) > 0) {
?>
    <div id="tracked_tables">
    <h3><?php echo __('Tracked tables');?></h3>
<?php
}
71. Testing untestable code
ContentProvider for the Frame
public class MyContentProvider extends
    AbstractContentProvider {
    public SlotConfiguration computeSlots(
        FeatureConfiguration config) {
        SlotConfiguration sl = new SlotConfiguration();
        if(config.hasFeature("unittest")) {
            sl.put("Factory", "FactoryMock");
        } else {
            sl.put("Factory", "EngineFactory");
        }
        return sl;
    }
}