testing untestable code - phpconpl11

74
Testing untestable code

Upload: stephan-hochdoerfer

Post on 10-May-2015

1.194 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Testing untestable code - phpconpl11

Testing untestable code

Page 2: Testing untestable code - phpconpl11

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 - phpconpl11

Testing untestable code

No excuse for writing bad code!

Page 4: Testing untestable code - phpconpl11

Not to freak out!

Testing untestable code

Page 5: Testing untestable code - phpconpl11

Testing untestable code

Creativity matters!

Page 6: Testing untestable code - phpconpl11

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 - phpconpl11

What is „untestable Code“?

Testing untestable code

Page 8: Testing untestable code - phpconpl11

s

Testing untestable code

1. Wrong object construction

“new” is evil!

Page 9: Testing untestable code - phpconpl11

Testing untestable code

2. Tight coupling

Page 10: Testing untestable code - phpconpl11

No code reuse!

Testing untestable code

Page 11: Testing untestable code - phpconpl11

No isolation → not testable!

Testing untestable code

Page 12: Testing untestable code - phpconpl11

Testing untestable code

3. Uncertainty

Page 13: Testing untestable code - phpconpl11

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 - phpconpl11

Testing untestable code

SUTSUTUnittestUnittest

In a perfect world...

Page 15: Testing untestable code - phpconpl11

Testing untestable code

SUTSUTUnittestUnittest

Legacy code is not perfect...

DependencyDependency

DependencyDependency

Page 16: Testing untestable code - phpconpl11

Testing untestable code

SUTSUTUnittestUnittest

Legacy code is not perfect...

DependencyDependency

DependencyDependency

...

...

Page 17: Testing untestable code - phpconpl11

Testing untestable code

SUTSUTUnittestUnittest

Legacy code is not perfect...

DependencyDependency

DependencyDependency

...

...

Page 18: Testing untestable code - phpconpl11

Testing untestable code

How to get „testable“ code?

Page 19: Testing untestable code - phpconpl11

Testing untestable code

How to get „testable“ code?

Refactoring

Page 20: Testing untestable code - phpconpl11

Testing untestable code

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

Martin Fowler, Refactoring

Page 21: Testing untestable code - phpconpl11

Testing untestable code

Hope? - Nope...

Page 22: Testing untestable code - phpconpl11

Testing untestable code

Which path to take?

Page 23: Testing untestable code - phpconpl11

Testing untestable code

Which path to take?

Do not change existing code!

Page 24: Testing untestable code - phpconpl11

Testing untestable code

Examples

Object Construction External resources Language issues

Page 25: Testing untestable code - phpconpl11

Testing untestable code

Object construction

<?phpclass Car {

private $Engine;

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

}

}

Page 26: Testing untestable code - phpconpl11

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

Page 27: Testing untestable code - phpconpl11

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 - phpconpl11

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 - phpconpl11

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 - phpconpl11

Testing untestable code

Object construction – Stream Wrapper

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

Page 31: Testing untestable code - phpconpl11

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 - phpconpl11

Testing untestable code

Object construction – Namespaces

<?phpclass Car {

private $Engine;

public function __construct($sEngine) {$this->Engine = \Car\Engine::

getByType($sEngine);}

}

Page 33: Testing untestable code - phpconpl11

Testing untestable code

External resources

Page 34: Testing untestable code - phpconpl11

Testing untestable code

External resources

Database Webservice

Filesystem Mailserver

Page 35: Testing untestable code - phpconpl11

Testing untestable code

External resources – Mock database

Page 36: Testing untestable code - phpconpl11

Testing untestable code

External resources – Mock database

Provide own implementation

Page 37: Testing untestable code - phpconpl11

Testing untestable code

External resources – Mock database

ZF example:

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

Page 38: Testing untestable code - phpconpl11

Testing untestable code

External resources – Mock database

PHPUnit_Extensions_Database_TestCase

Page 39: Testing untestable code - phpconpl11

Testing untestable code

External resources – Mock database

Proxy for your SQL Server

Page 40: Testing untestable code - phpconpl11

Testing untestable code

External resources – Mock webservice

Page 41: Testing untestable code - phpconpl11

Testing untestable code

External resources – Mock webservice

Provide own implementation

Page 42: Testing untestable code - phpconpl11

Testing untestable code

External resources – Mock webservice

Host redirect via /etc/hosts

Page 43: Testing untestable code - phpconpl11

Testing untestable code

External resources – Mock filesystem

Page 44: Testing untestable code - phpconpl11

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 45: Testing untestable code - phpconpl11

Testing untestable code

External resources – Mock Mailserver

Page 46: Testing untestable code - phpconpl11

Testing untestable code

External resources – Mock Mailserver

Use fake mail server

Page 47: Testing untestable code - phpconpl11

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 48: Testing untestable code - phpconpl11

Testing untestable code

Dealing with language issues

Page 49: Testing untestable code - phpconpl11

Testing untestable code

Dealing with language issues

Testing your privates?

Page 50: Testing untestable code - phpconpl11

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 51: Testing untestable code - phpconpl11

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 52: Testing untestable code - phpconpl11

Testing untestable code

Dealing with language issues

Overwrite internal functions?

Page 53: Testing untestable code - phpconpl11

Testing untestable code

Dealing with language issues

pecl install runkit-0.9

Page 54: Testing untestable code - phpconpl11

Testing untestable code

Dealing with language issues - Runkit

<?php

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

runkit_function_redefine('mail','','returntrue;');

?>

Page 55: Testing untestable code - phpconpl11

Testing untestable code

Dealing with language issues

pecl install funcall-0.3.0alpha

Page 56: Testing untestable code - phpconpl11

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 57: Testing untestable code - phpconpl11

Testing untestable code

What else?

Page 58: Testing untestable code - phpconpl11

What else?

Testing untestable code

Generative Programming

Page 59: Testing untestable code - phpconpl11

Testing untestable code

Generative Programming

ConfigurationConfiguration

Implementationcomponents

Implementationcomponents

Generatorapplication

Generatorapplication

ProductProductGeneratorGenerator

1 ... n

Page 60: Testing untestable code - phpconpl11

Testing untestable code

Generative Programming

ConfigurationConfiguration

Implementationcomponents

Implementationcomponents

Generatorapplication

Generatorapplication

GeneratorGenerator

ApplicationApplication

TestcasesTestcases

Page 61: Testing untestable code - phpconpl11

Testing untestable code

Generative Programming

A frame is a data structure for representing knowledge.

Page 62: Testing untestable code - phpconpl11

Testing untestable code

A Frame instance

<?phpclass Car {

private $Engine;

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

getByType($sEngine);}

}

Page 63: Testing untestable code - phpconpl11

Testing untestable code

The Frame controller

public class MyFrameController extendsSimpleFrameController {

public void execute(Frame frame, FeatureConfigconfig) {

if(config.hasFeature("unittest")) { frame.setSlot("Factory", "FactoryMock");}else { frame.setSlot("Factory", "EngineFactory");}

}}

Page 64: Testing untestable code - phpconpl11

Testing untestable code

Generated result - Testcase

<?phpclass Car {

private $Engine;

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

getByType($sEngine);}

}

Page 65: Testing untestable code - phpconpl11

Testing untestable code

Generated result - Application

<?phpclass Car {

private $Engine;

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

getByType($sEngine);}

}

Page 66: Testing untestable code - phpconpl11

Testing untestable code

What is possible?

Page 67: Testing untestable code - phpconpl11

Testing untestable code

What is possible?

Show / hide parts of the code

Page 68: Testing untestable code - phpconpl11

Testing untestable code

What is possible?

Change content of global vars!

Page 69: Testing untestable code - phpconpl11

Testing untestable code

What is possible?

Define pre- or postfixes!

Page 70: Testing untestable code - phpconpl11

Testing untestable code

Is it worth it?

Page 71: Testing untestable code - phpconpl11

Testing untestable code

Conclusions

Change your mindset to write testable code!

Page 72: Testing untestable code - phpconpl11

Testing untestable code

Conclusions

PHP is a swiss-army knife. Use it that way!

Page 73: Testing untestable code - phpconpl11

http://joind.in/3922

Page 74: Testing untestable code - phpconpl11

Testing untestable code

Bildquellen

http://www.flickr.com/photos/andresrueda/3452940751/

http://www.flickr.com/photos/andresrueda/3455410635/