74
Testing untestable code

Testing untestable code - DCHH

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Testing untestable code - DCHH

Testing untestable code

Page 2: Testing untestable code - DCHH

Testing untestable code

Über mich

Stephan Hochdörfer, bitExpert AG

Department Manager Research Labs

PHP Fanboy seit 1999

[email protected]

@shochdoerfer

Page 3: Testing untestable code - DCHH

Testing untestable code

Keine Entschuldigung für schlechten Code!

Page 4: Testing untestable code - DCHH

Nicht ausflippen!

Testing untestable code

Page 5: Testing untestable code - DCHH

Testing untestable code

Kreativität zählt!

Page 6: Testing untestable code - DCHH

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

Was ist „untestbarer Code“?

Testing untestable code

Page 8: Testing untestable code - DCHH

s

Testing untestable code

1. Falsche Instantiierung

“new” is evil!

Page 9: Testing untestable code - DCHH

Testing untestable code

2. Starke Kopplung

Page 10: Testing untestable code - DCHH

Keine Wiederverwendbarkeit

Testing untestable code

Page 11: Testing untestable code - DCHH

Nicht isolierbar, nicht testbar!

Testing untestable code

Page 12: Testing untestable code - DCHH

Testing untestable code

3. Ungewissheit

Page 13: Testing untestable code - DCHH

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

Testing untestable code

SUTSUTUnittestUnittest

In einer perfekten Welt..

Page 15: Testing untestable code - DCHH

Testing untestable code

SUTSUTUnittestUnittest

Legacy code ist nicht perfekt...

AbhängigeKlasse

AbhängigeKlasse

AbhängigeKlasse

AbhängigeKlasse

Page 16: Testing untestable code - DCHH

Testing untestable code

SUTSUTUnittestUnittest

Legacy code ist nicht perfekt...

AbhängigeKlasse

AbhängigeKlasse

AbhängigeKlasse

AbhängigeKlasse

...

...

Page 17: Testing untestable code - DCHH

Testing untestable code

SUTSUTUnittestUnittest

Legacy code ist nicht perfekt...

AbhängigeKlasse

AbhängigeKlasse

AbhängigeKlasse

AbhängigeKlasse

...

...

Page 18: Testing untestable code - DCHH

Testing untestable code

Wie erzeugt man „testbaren Code“?

Page 19: Testing untestable code - DCHH

Testing untestable code

Wie erzeugt man „testbaren Code“?

Refactoring

Page 20: Testing untestable code - DCHH

Testing untestable code

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

Martin Fowler, Refactoring

Page 21: Testing untestable code - DCHH

Testing untestable code

Hoffnung? ...ist nicht genug

Page 22: Testing untestable code - DCHH

Testing untestable code

Wohin führt die Reise?

Page 23: Testing untestable code - DCHH

Testing untestable code

Wohin führt die Reise?

Vorhandenen Code nicht ändern!

Page 24: Testing untestable code - DCHH

Testing untestable code

Beispiele

Objekterzeugung Externe Ressourcen Sprachbarrieren

Page 25: Testing untestable code - DCHH

Testing untestable code

Objekterzeugung

<?phpclass Car {

private $engine;

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

}

}

Page 26: Testing untestable code - DCHH

Testing untestable code

Objekterzeugung - Autoload

<?phpfunction run_autoload($class) {

$fileToInclude = strtolower($class).'.php';if(strtolower($class) == 'engine') {

$fileToInclude = '/custom/mocks/'. $fileToInclude;

}include($fileToInclude);

}

// Testcasespl_autoload_register('run_autoload');$car = new Car('Diesel');echo $car->run();

Page 27: Testing untestable code - DCHH

Testing untestable code

Objekterzeugung

<?phpinclude('Engine.php');

class Car {private $engine;

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

}}

Page 28: Testing untestable code - DCHH

Testing untestable code

Objekterzeugung - include_path

<?phpini_set('include_path',

'/custom/mocks/'.PATH_SEPARATOR.ini_get('include_path'));

// Testcaseinclude('car.php');

$car = new Car('Diesel');echo $car->run();

Page 29: Testing untestable code - DCHH

Testing untestable code

Objekterzeugung – 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 - DCHH

Testing untestable code

Objekterzeugung – Stream Wrapper

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

Page 31: Testing untestable code - DCHH

Testing untestable code

Objekterzeugung – 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 - DCHH

Testing untestable code

Objekterzeugung – Namespaces

<?phpclass Car {

private $engine;

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

getByType($engine);}

}

Page 33: Testing untestable code - DCHH

Testing untestable code

Externe Ressourcen

Page 34: Testing untestable code - DCHH

Testing untestable code

Externe Ressourcen

Datenbank Webservice

Dateisystem Mailserver

Page 35: Testing untestable code - DCHH

Testing untestable code

Externe Ressourcen – Datenbank mocken

Page 36: Testing untestable code - DCHH

Testing untestable code

Externe Ressourcen – Datenbank mocken

Eigene Implementierung anbieten

Page 37: Testing untestable code - DCHH

Testing untestable code

Externe Ressourcen – Datenbank mocken

ZF Beispiel:

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

Page 38: Testing untestable code - DCHH

Testing untestable code

Externe Ressourcen – Datenbank mocken

PHPUnit_Extensions_Database_TestCase

Page 39: Testing untestable code - DCHH

Testing untestable code

Externe Ressourcen – Datenbank mocken

Proxy for den SQL Server

Page 40: Testing untestable code - DCHH

Testing untestable code

Externe Ressourcen – Webservice mocken

Page 41: Testing untestable code - DCHH

Testing untestable code

Externe Ressourcen – Webservice mocken

Eigene Implementierung anbieten

Page 42: Testing untestable code - DCHH

Testing untestable code

Externe Ressourcen – Webservice mocken

Host Alias via /etc/hosts

Page 43: Testing untestable code - DCHH

Testing untestable code

Externe Ressourcen – Dateisytem mocken

Page 44: Testing untestable code - DCHH

Testing untestable code

Externe Ressourcen – Dateisystem mocken

<?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 - DCHH

Testing untestable code

Externe Ressourcen – Mailserver mocken

Page 46: Testing untestable code - DCHH

Testing untestable code

Externe Ressourcen – Mailserver mocken

fake mail server verwenden

Page 47: Testing untestable code - DCHH

Testing untestable code

Externe Ressourcen – Mailserver mocken

$ 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 - DCHH

Testing untestable code

Sprachbarrieren

Page 49: Testing untestable code - DCHH

Testing untestable code

Sprachbarrieren

private Methoden testen?

Page 50: Testing untestable code - DCHH

Testing untestable code

Sprachbarrieren

<?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 - DCHH

Testing untestable code

Sprachbarrieren

$myClass = new MyClass();

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

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

Page 52: Testing untestable code - DCHH

Testing untestable code

Sprachbarrieren

Interne Funktionen überschreiben?

Page 53: Testing untestable code - DCHH

Testing untestable code

Sprachbarrieren - Runkit

pecl install runkit-0.9

Page 54: Testing untestable code - DCHH

Testing untestable code

Sprachbarrieren - Runkit

<?php

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

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

?>

Page 55: Testing untestable code - DCHH

Testing untestable code

Spielraum?

Page 56: Testing untestable code - DCHH

Testing untestable code

Abstrahieren du sollst!

Page 57: Testing untestable code - DCHH

Was sonst?

Testing untestable code

Generative Programmierung

Page 58: Testing untestable code - DCHH

Generative Programmierung

Testing untestable code

GeneratorGenerator

Page 59: Testing untestable code - DCHH

Generative Programmierung

Testing untestable code

Konfiguration(DSL)

Konfiguration(DSL)

GeneratorGenerator

Page 60: Testing untestable code - DCHH

Generative Programmierung

Software generieren statt programmieren

Konfiguration(DSL)

Konfiguration(DSL)

Implementierungs-komponenten

Implementierungs-komponenten GeneratorGenerator

Page 61: Testing untestable code - DCHH

Generative Programmierung

Testing untestable code

Konfiguration(DSL)

Konfiguration(DSL)

Implementierungs-komponenten

Implementierungs-komponenten GeneratorGenerator

ProduktProdukt

1..n

Page 62: Testing untestable code - DCHH

Generative Programmierung

Testing untestable code

Konfiguration(DSL)

Konfiguration(DSL)

Implementierungs-komponenten

Implementierungs-komponenten GeneratorGenerator

ApplikationApplikation

TestsTests

Page 63: Testing untestable code - DCHH

Testing untestable code

Generative Programmierung

Ein Frame ist eine Datenstrukturdie Wissen repräsentiert.

Page 64: Testing untestable code - DCHH

Testing untestable code

Eine Frame Instanz

<?phpclass Car {

private $engine;

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

getByType($engine);}

}

Page 65: Testing untestable code - DCHH

Testing untestable code

Der 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 66: Testing untestable code - DCHH

Testing untestable code

Nach der Generierung - Testcase

<?phpclass Car {

private $engine;

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

getByType($engine);}

}

Page 67: Testing untestable code - DCHH

Testing untestable code

Nach der Generierung - Applikation

<?phpclass Car {

private $engine;

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

getByType($engine);}

}

Page 68: Testing untestable code - DCHH

Testing untestable code

Was ist möglich?

Page 69: Testing untestable code - DCHH

Testing untestable code

Was ist möglich?

Extraktion von Codezeilen

Page 70: Testing untestable code - DCHH

Testing untestable code

Was ist möglich?

Globale Inhalte verändern

Page 71: Testing untestable code - DCHH

Testing untestable code

Was ist möglich?

Pre- oder Postfixes für Methoden

Page 72: Testing untestable code - DCHH

Testing untestable code

Wie weit sollte man gehen?

Page 73: Testing untestable code - DCHH

Vielen Dank!

Page 74: Testing untestable code - DCHH

Testing untestable code

Bildquellen

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

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