testing untestable code - oscon 2012

72
Testing untestable code Stephan Hochdörfer, bitExpert AG

Upload: stephan-hochdoerfer

Post on 13-Jan-2015

804 views

Category:

Technology


0 download

DESCRIPTION

 

TRANSCRIPT

Page 1: Testing untestable code - oscon 2012

Testing untestable codeStephan Hochdörfer, bitExpert AG

Page 2: Testing untestable code - oscon 2012

Testing untestable code

About me

Stephan Hochdörfer, bitExpert AG

Department Manager Research Labs

enjoying PHP since 1999

[email protected]

@shochdoerfer

Page 3: Testing untestable code - oscon 2012

Testing untestable code

No excuse for writing bad code!

Page 4: Testing untestable code - oscon 2012
Page 5: Testing untestable code - oscon 2012
Page 6: Testing untestable code - oscon 2012

Testing untestable code

"There is no secret to writing tests, there are only secrets to write

testable code!" Miško Hevery

Page 7: Testing untestable code - oscon 2012

What is „untestable code“?

Testing untestable code

Page 8: Testing untestable code - oscon 2012
Page 9: Testing untestable code - oscon 2012
Page 10: Testing untestable code - oscon 2012
Page 11: Testing untestable code - oscon 2012
Page 12: Testing untestable code - oscon 2012
Page 13: Testing untestable code - oscon 2012

Testing untestable code

"...our test strategy requires us to have more control [...] of the sut."Gerard Meszaros, xUnit Test Patterns: Refactoring Test

Code

Page 14: Testing untestable code - oscon 2012

Testing untestable code

SUTSUTUnittestUnittest

In a perfect world...

Page 15: Testing untestable code - oscon 2012

Testing untestable code

SUTSUTUnittestUnittest

Legacy code is not perfect...

DependencyDependency

DependencyDependency

Page 16: Testing untestable code - oscon 2012

Testing untestable code

SUTSUTUnittestUnittest

Legacy code is not perfect...

DependencyDependency

DependencyDependency

...

...

Page 17: Testing untestable code - oscon 2012

Testing untestable code

SUTSUTUnittestUnittest

Legacy code is not perfect...

DependencyDependency

DependencyDependency

...

...

Page 18: Testing untestable code - oscon 2012

Testing untestable code

How to get „testable“ code?

Page 19: Testing untestable code - oscon 2012

Testing untestable code

How to get „testable“ code?

Refactoring

Page 20: Testing untestable code - oscon 2012

Testing untestable code

"Before you start refactoring, check that you have a solid suite of

tests."Martin Fowler, Refactoring

Page 21: Testing untestable code - oscon 2012
Page 22: Testing untestable code - oscon 2012

Testing untestable code

Which path to take?

Page 23: Testing untestable code - oscon 2012

Testing untestable code

Which path to take?

Do not change existing code!

Page 24: Testing untestable code - oscon 2012

Testing untestable code

Examples

Object Construction External resources Language issues

Page 25: Testing untestable code - oscon 2012

Testing untestable code

Object construction<?phpclass Car {

private $Engine;

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

}

}

Page 26: Testing untestable code - oscon 2012

Testing untestable code

Object construction - 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 27: Testing untestable code - oscon 2012

Testing untestable code

Object construction<?phpinclude('Engine.php');

class Car {private $Engine;

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

}}

Page 28: Testing untestable code - oscon 2012

Testing untestable code

Object construction - 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 29: Testing untestable code - oscon 2012

Testing untestable code

Object construction – Stream Wrapper<?phpclass 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;  }}

Page 30: Testing untestable code - oscon 2012

Testing untestable code

Object construction – Stream Wrapperstream_wrapper_unregister('file');stream_wrapper_register('file', 'CustomWrapper');

Page 31: Testing untestable code - oscon 2012

Testing untestable code

Object construction – Stream Wrapper<?phpclass CustomWrapper {

private $_handler;

function stream_read($count) {$content = fread($this­>_handler, $count);$content = str_replace('Engine::getByType',

       'AbstractEngine::get', $content);return $content;

}}

Page 32: Testing untestable code - oscon 2012

Testing untestable code

External resources

Page 33: Testing untestable code - oscon 2012

Testing untestable code

External resources

Database Webservice

Filesystem Mailserver

Page 34: Testing untestable code - oscon 2012

Testing untestable code

External resources – Mock database

Page 35: Testing untestable code - oscon 2012

Testing untestable code

External resources – Mock database

Provide own implementation

Page 36: Testing untestable code - oscon 2012

Testing untestable code

External resources – Mock database

ZF example:$db = new Custom_Db_Adapter(array());Zend_Db_Table::setDefaultAdapter($db);

Page 37: Testing untestable code - oscon 2012

Testing untestable code

External resources – Mock database

PHPUnit_Extensions_Database_TestCase

Page 38: Testing untestable code - oscon 2012

Testing untestable code

External resources – Mock database

Proxy for your SQL Server

Page 39: Testing untestable code - oscon 2012

Testing untestable code

External resources – Mock webservice

Page 40: Testing untestable code - oscon 2012

Testing untestable code

External resources – Mock webservice

Provide own implementation

Page 41: Testing untestable code - oscon 2012

Testing untestable code

External resources – Mock webservice

Host redirect via /etc/hosts

Page 42: Testing untestable code - oscon 2012

Testing untestable code

External resources – Mock filesystem

Page 43: Testing untestable code - oscon 2012

Testing untestable code

External resources – Mock filesystem<?php

// set up test environmemtvfsStream::setup('exampleDir');

// create directory in test enviromentmkdir(vfsStream::url('exampleDir').'/sample/');

// check if directory was createdecho vfsStreamWrapper::getRoot()­>hasChild('sample');

Page 44: Testing untestable code - oscon 2012

Testing untestable code

External resources – Mock Mailserver

Page 45: Testing untestable code - oscon 2012

Testing untestable code

External resources – Mock Mailserver

Use fake mail server

Page 46: Testing untestable code - oscon 2012

Testing untestable code

External resources – Mock Mailserver$ cat /etc/php5/php.ini | grep sendmail_pathsendmail_path=/usr/local/bin/logmail

$ cat /usr/local/bin/logmailcat >> /tmp/logmail.log

Page 47: Testing untestable code - oscon 2012

Testing untestable code

Dealing with language issues

Page 48: Testing untestable code - oscon 2012

Testing untestable code

Dealing with language issues

Testing your privates?

Page 49: Testing untestable code - oscon 2012

Testing untestable code

Dealing with language issues<?phpclass CustomWrapper {

private $_handler;

function stream_read($count) {$content = fread($this­>_handler, $count);$content = str_replace(

         'private function',         'public function',          $content      );

return $content;}

}

Page 50: Testing untestable code - oscon 2012

Testing untestable code

Dealing with language issues$myClass = new MyClass();

$reflectionClass  = new ReflectionClass('MyClass');$reflectionMethod = $reflectionClass­>

getMethod('mydemo');$reflectionMethod­>setAccessible(true);$reflectionMethod­>invoke($myClass);

Page 51: Testing untestable code - oscon 2012

Testing untestable code

Dealing with language issues

Overwrite internal functions?

Page 52: Testing untestable code - oscon 2012

Testing untestable code

Dealing with language issues

pecl install runkit-0.9

Page 53: Testing untestable code - oscon 2012

Testing untestable code

Dealing with language issues - Runkit<?php

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

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

?>

Page 54: Testing untestable code - oscon 2012

Testing untestable code

Dealing with language issues

pecl install funcall-0.3.0alpha

Page 55: Testing untestable code - oscon 2012

Testing untestable code

Dealing with language issues - Funcall

<?phpfunction 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'));

Page 56: Testing untestable code - oscon 2012

Testing untestable code

Dealing with language issues

funcall for methods?

Page 57: Testing untestable code - oscon 2012

Testing untestable code

Dealing with language issues

git clone https://github/juliens/AOP

Page 58: Testing untestable code - oscon 2012

Testing untestable code

Dealing with language issues - AOP

<?php

aop_add_after('Car::drive*', 'adviceForDrive');

Page 59: Testing untestable code - oscon 2012

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);

Page 60: Testing untestable code - oscon 2012
Page 61: Testing untestable code - oscon 2012

What else?

Testing untestable code

Generative Programming

Page 62: Testing untestable code - oscon 2012

Testing untestable code

Generative Programming

Configuration(DSL)

Configuration(DSL)

Implementation-components

Implementation-components GeneratorGenerator

ProductProduct

1..n

Page 63: Testing untestable code - oscon 2012

Testing untestable code

Generative Programming

Configuration(DSL)

Configuration(DSL)

Implementation-components

Implementation-components GeneratorGenerator

Customer 1Customer 1

Customer 2Customer 2

Page 64: Testing untestable code - oscon 2012

Testing untestable code

Generative Programming

Configuration(DSL)

Configuration(DSL)

Implementation-components

Implementation-components GeneratorGenerator Prod.

Enviroment

Prod.Enviroment

TestEnviroment

TestEnviroment

Page 65: Testing untestable code - oscon 2012

Testing untestable code

Generative Programming

A frame is a data structure for representing knowledge.

Page 66: Testing untestable code - oscon 2012

Testing untestable code

Frame<?phpclass Car {

private $Engine;

public function __construct($sEngine) {$this­>Engine = <!{Factory}!>::

getByType($sEngine);}

}

Page 67: Testing untestable code - oscon 2012

Testing untestable code

ContentProvider for the Framepublic 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;    }}

Page 68: Testing untestable code - oscon 2012

Testing untestable code

Generated result – Test Enviroment<?phpclass Car {

private $Engine;

public function __construct($sEngine) {$this­>Engine = FactoryMock::

getByType($sEngine);}

}

Page 69: Testing untestable code - oscon 2012

Testing untestable code

Generated result – Prod. Enviroment<?phpclass Car {

private $Engine;

public function __construct($sEngine) {$this­>Engine = EngineFactory::

getByType($sEngine);}

}

Page 70: Testing untestable code - oscon 2012

Curious for more?

Testing untestable code

http://replicatorframework.org

Page 71: Testing untestable code - oscon 2012

Thank you!

Page 72: Testing untestable code - oscon 2012

Please rate: http://bit.ly/ML0alS