71
Testing untestable code

Testing untestable code - gearconf11

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Testing untestable code - gearconf11

Testing untestable code

Page 2: Testing untestable code - gearconf11

Testing untestable code

Über mich

Stephan Hochdörfer, bitExpert AG

Department Manager Research Labs

[email protected]

@shochdoerfer

Page 3: Testing untestable code - gearconf11

Testing untestable code

Keine Entschuldigung für schlechten Code!

Page 4: Testing untestable code - gearconf11

Nicht ausflippen!

Testing untestable code

Page 5: Testing untestable code - gearconf11

Testing untestable code

Kreativität zählt!

Page 6: Testing untestable code - gearconf11

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

Was ist „untestbarer Code“?

Testing untestable code

Page 8: Testing untestable code - gearconf11

s

Testing untestable code

1. Falsche Instantiierung

“new” is evil!

Page 9: Testing untestable code - gearconf11

Testing untestable code

2. Starke Kopplung

Page 10: Testing untestable code - gearconf11

Keine Wiederverwendbarkeit

Testing untestable code

Page 11: Testing untestable code - gearconf11

Nicht isolierbar, nicht testbar!

Testing untestable code

Page 12: Testing untestable code - gearconf11

Testing untestable code

3. Ungewissheit

Page 13: Testing untestable code - gearconf11

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

Testing untestable code

SUTSUTUnittestUnittest

In einer perfekten Welt..

Page 15: Testing untestable code - gearconf11

Testing untestable code

SUTSUTUnittestUnittest

Legacy code ist nicht perfekt...

AbhängigeKlasse

AbhängigeKlasse

AbhängigeKlasse

AbhängigeKlasse

Page 16: Testing untestable code - gearconf11

Testing untestable code

SUTSUTUnittestUnittest

Legacy code ist nicht perfekt...

AbhängigeKlasse

AbhängigeKlasse

AbhängigeKlasse

AbhängigeKlasse

...

...

Page 17: Testing untestable code - gearconf11

Testing untestable code

SUTSUTUnittestUnittest

Legacy code ist nicht perfekt...

AbhängigeKlasse

AbhängigeKlasse

AbhängigeKlasse

AbhängigeKlasse

...

...

Page 18: Testing untestable code - gearconf11

Testing untestable code

Wie erzeugt man „testbaren Code“?

Page 19: Testing untestable code - gearconf11

Testing untestable code

Wie erzeugt man „testbaren Code“?

Refactoring

Page 20: Testing untestable code - gearconf11

Testing untestable code

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

Martin Fowler, Refactoring

Page 21: Testing untestable code - gearconf11

Testing untestable code

Hoffnung? ...ist nicht genug

Page 22: Testing untestable code - gearconf11

Testing untestable code

Wohin führt die Reise?

Page 23: Testing untestable code - gearconf11

Testing untestable code

Wohin führt die Reise?

Vorhandenen Code nicht ändern!

Page 24: Testing untestable code - gearconf11

Testing untestable code

Beispiele

Objekterzeugung Externe Ressourcen Sprachbarrieren

Page 25: Testing untestable code - gearconf11

Testing untestable code

Objekterzeugung

public class Car {private Engine engine;

public Car(String engine) {this.engine = EngineFactory.getByType(engine);

}}

Page 26: Testing untestable code - gearconf11

Testing untestable code

Objekterzeugung - Autoload

public class MyLoader extends ClassLoader {protected Class findClass(String name)

throws ClassNotFoundException{

try {String path = name.replace('.', '/');// @TODO: change path and read file, // @TODO: define package// @TODO: define class

}catch(Exception e){

throw new ClassNotFoundException(name);}

}}

Page 27: Testing untestable code - gearconf11

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 28: Testing untestable code - gearconf11

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 29: Testing untestable code - gearconf11

Testing untestable code

Externe Ressourcen

Page 30: Testing untestable code - gearconf11

Testing untestable code

Externe Ressourcen

Datenbank Webservice

Dateisystem Mailserver

Page 31: Testing untestable code - gearconf11

Testing untestable code

Externe Ressourcen – Datenbank mocken

Page 32: Testing untestable code - gearconf11

Testing untestable code

Externe Ressourcen – Datenbank mocken

Eigene Implementierung anbieten

Page 33: Testing untestable code - gearconf11

Testing untestable code

Externe Ressourcen – Datenbank mocken

junit + dbunit

Page 34: Testing untestable code - gearconf11

Testing untestable code

Externe Ressourcen – Datenbank mocken

PHPUnit_Extensions_Database_TestCase

Page 35: Testing untestable code - gearconf11

Testing untestable code

Externe Ressourcen – Datenbank mocken

Proxy für den SQL Server

Page 36: Testing untestable code - gearconf11

Testing untestable code

Externe Ressourcen – Webservice mocken

Page 37: Testing untestable code - gearconf11

Testing untestable code

Externe Ressourcen – Webservice mocken

Eigene Implementierung anbieten

Page 38: Testing untestable code - gearconf11

Testing untestable code

Externe Ressourcen – Webservice mocken

Host Alias via /etc/hosts

Page 39: Testing untestable code - gearconf11

Testing untestable code

Externe Ressourcen – Dateisytem mocken

Page 40: Testing untestable code - gearconf11

Testing untestable code

Externe Ressourcen – Dateisytem mocken

Commons-VFS

Page 41: Testing untestable code - gearconf11

Testing untestable code

Externe Ressourcen – Dateisytem mocken

vfsStream

Page 42: Testing untestable code - gearconf11

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 43: Testing untestable code - gearconf11

Testing untestable code

Externe Ressourcen – Mailserver mocken

Page 44: Testing untestable code - gearconf11

Testing untestable code

Externe Ressourcen – Mailserver mocken

fake mail server verwenden

Page 45: Testing untestable code - gearconf11

Testing untestable code

Sprachbarrieren

Page 46: Testing untestable code - gearconf11

Testing untestable code

Sprachbarrieren

private Methoden testen?

Page 47: Testing untestable code - gearconf11

Testing untestable code

Sprachbarrieren

final Method methods[] =o.getClass().getDeclaredMethods();for (int i = 0; i < methods.length; ++i) {

if (methodName.equals(methods[i].getName())) {try {

methods[i].setAccessible(true); return methods[i].invoke(o, params);} catch (IllegalAccessException ex) {}catch (InvocationTargetException ite) {}

}return null;

}

Page 48: Testing untestable code - gearconf11

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 49: Testing untestable code - gearconf11

Testing untestable code

Sprachbarrieren

Interne Funktionen überschreiben?

Page 50: Testing untestable code - gearconf11

Testing untestable code

Sprachbarrieren - Runkit

pecl install runkit-0.9

Page 51: Testing untestable code - gearconf11

Testing untestable code

Sprachbarrieren - Runkit

<?php

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

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

?>

Page 52: Testing untestable code - gearconf11

Testing untestable code

Spielraum?

Page 53: Testing untestable code - gearconf11

Testing untestable code

Abstrahieren du sollst!

Page 54: Testing untestable code - gearconf11

Was sonst?

Testing untestable code

Generative Programmierung

Page 55: Testing untestable code - gearconf11

Generative Programmierung

Testing untestable code

GeneratorGenerator

Page 56: Testing untestable code - gearconf11

Generative Programmierung

Testing untestable code

Konfiguration(DSL)

Konfiguration(DSL)

GeneratorGenerator

Page 57: Testing untestable code - gearconf11

Generative Programmierung

Software generieren statt programmieren

Konfiguration(DSL)

Konfiguration(DSL)

Implementierungs-komponenten

Implementierungs-komponenten GeneratorGenerator

Page 58: Testing untestable code - gearconf11

Generative Programmierung

Testing untestable code

Konfiguration(DSL)

Konfiguration(DSL)

Implementierungs-komponenten

Implementierungs-komponenten GeneratorGenerator

ProduktProdukt

1..n

Page 59: Testing untestable code - gearconf11

Generative Programmierung

Testing untestable code

Konfiguration(DSL)

Konfiguration(DSL)

Implementierungs-komponenten

Implementierungs-komponenten GeneratorGenerator

ApplikationApplikation

TestsTests

Page 60: Testing untestable code - gearconf11

Testing untestable code

Generative Programmierung

Ein Frame ist eine Datenstrukturdie Wissen repräsentiert.

Page 61: Testing untestable code - gearconf11

Testing untestable code

Eine Frame Instanz

public class Car {private Engine engine;

public Car(String engine) {this.engine = <!{Factory}!>.getByType(engine);

}}

Page 62: Testing untestable code - gearconf11

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 63: Testing untestable code - gearconf11

Testing untestable code

Nach der Generierung - Testcase

public class Car {private Engine engine;

public Car(String engine) {this.engine = FactoryMock.getByType(engine);

}}

Page 64: Testing untestable code - gearconf11

Testing untestable code

Nach der Generierung - Applikation

public class Car {private Engine engine;

public Car(String engine) {this.engine = EngineFactory.getByType(engine);

}}

Page 65: Testing untestable code - gearconf11

Testing untestable code

Was ist möglich?

Page 66: Testing untestable code - gearconf11

Testing untestable code

Was ist möglich?

Extraktion von Codezeilen

Page 67: Testing untestable code - gearconf11

Testing untestable code

Was ist möglich?

Globale Inhalte verändern

Page 68: Testing untestable code - gearconf11

Testing untestable code

Was ist möglich?

Pre- oder Postfixes für Methoden

Page 69: Testing untestable code - gearconf11

Testing untestable code

Wie weit sollte man gehen?

Page 70: Testing untestable code - gearconf11

Vielen Dank!

Page 71: Testing untestable code - gearconf11

Testing untestable code

Bildquellen

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

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