testing untestable code - dchh
Post on 13-Jan-2015
1.005 Views
Preview:
DESCRIPTION
TRANSCRIPT
Testing untestable code
Testing untestable code
Über mich
Stephan Hochdörfer, bitExpert AG
Department Manager Research Labs
PHP Fanboy seit 1999
S.Hochdoerfer@bitExpert.de
@shochdoerfer
Testing untestable code
Keine Entschuldigung für schlechten Code!
Nicht ausflippen!
Testing untestable code
Testing untestable code
Kreativität zählt!
Testing untestable code
"There is no secret to writing tests, there are only secrets to write
testable code!" Miško Hevery
Was ist „untestbarer Code“?
Testing untestable code
s
Testing untestable code
1. Falsche Instantiierung
“new” is evil!
Testing untestable code
2. Starke Kopplung
Keine Wiederverwendbarkeit
Testing untestable code
Nicht isolierbar, nicht testbar!
Testing untestable code
Testing untestable code
3. Ungewissheit
Testing untestable code
"...our test strategy requires us to have more control [...] of the sut."
Gerard Meszaros, xUnit Test Patterns: Refactoring Test Code
Testing untestable code
SUTSUTUnittestUnittest
In einer perfekten Welt..
Testing untestable code
SUTSUTUnittestUnittest
Legacy code ist nicht perfekt...
AbhängigeKlasse
AbhängigeKlasse
AbhängigeKlasse
AbhängigeKlasse
Testing untestable code
SUTSUTUnittestUnittest
Legacy code ist nicht perfekt...
AbhängigeKlasse
AbhängigeKlasse
AbhängigeKlasse
AbhängigeKlasse
...
...
Testing untestable code
SUTSUTUnittestUnittest
Legacy code ist nicht perfekt...
AbhängigeKlasse
AbhängigeKlasse
AbhängigeKlasse
AbhängigeKlasse
...
...
Testing untestable code
Wie erzeugt man „testbaren Code“?
Testing untestable code
Wie erzeugt man „testbaren Code“?
Refactoring
Testing untestable code
"Before you start refactoring, check that you have a solid suite of tests."
Martin Fowler, Refactoring
Testing untestable code
Hoffnung? ...ist nicht genug
Testing untestable code
Wohin führt die Reise?
Testing untestable code
Wohin führt die Reise?
Vorhandenen Code nicht ändern!
Testing untestable code
Beispiele
Objekterzeugung Externe Ressourcen Sprachbarrieren
Testing untestable code
Objekterzeugung
<?phpclass Car {
private $engine;
public function __construct($engine) {$this->engine = Engine::getByType($engine);
}
}
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();
Testing untestable code
Objekterzeugung
<?phpinclude('Engine.php');
class Car {private $engine;
public function __construct($engine) {$this->engine = Engine::getByType($engine);
}}
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();
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; }}
Testing untestable code
Objekterzeugung – Stream Wrapper
stream_wrapper_unregister('file');stream_wrapper_register('file', 'CustomWrapper');
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;
}}
Testing untestable code
Objekterzeugung – Namespaces
<?phpclass Car {
private $engine;
public function __construct($engine) {$this->engine = \Car\Engine::
getByType($engine);}
}
Testing untestable code
Externe Ressourcen
Testing untestable code
Externe Ressourcen
Datenbank Webservice
Dateisystem Mailserver
Testing untestable code
Externe Ressourcen – Datenbank mocken
Testing untestable code
Externe Ressourcen – Datenbank mocken
Eigene Implementierung anbieten
Testing untestable code
Externe Ressourcen – Datenbank mocken
ZF Beispiel:
$db = new Custom_Db_Adapter(array());Zend_Db_Table::setDefaultAdapter($db);
Testing untestable code
Externe Ressourcen – Datenbank mocken
PHPUnit_Extensions_Database_TestCase
Testing untestable code
Externe Ressourcen – Datenbank mocken
Proxy for den SQL Server
Testing untestable code
Externe Ressourcen – Webservice mocken
Testing untestable code
Externe Ressourcen – Webservice mocken
Eigene Implementierung anbieten
Testing untestable code
Externe Ressourcen – Webservice mocken
Host Alias via /etc/hosts
Testing untestable code
Externe Ressourcen – Dateisytem mocken
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');
Testing untestable code
Externe Ressourcen – Mailserver mocken
Testing untestable code
Externe Ressourcen – Mailserver mocken
fake mail server verwenden
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
Testing untestable code
Sprachbarrieren
Testing untestable code
Sprachbarrieren
private Methoden testen?
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;}
Testing untestable code
Sprachbarrieren
$myClass = new MyClass();
$reflectionClass = new ReflectionClass('MyClass');$reflectionMethod = $reflectionClass->
getMethod('mydemo');$reflectionMethod->setAccessible(true);$reflectionMethod->invoke($myClass);
Testing untestable code
Sprachbarrieren
Interne Funktionen überschreiben?
Testing untestable code
Sprachbarrieren - Runkit
pecl install runkit-0.9
Testing untestable code
Sprachbarrieren - Runkit
<?php
ini_set('runkit.internal_override', '1');
runkit_function_redefine('mail','','returntrue;');
?>
Testing untestable code
Spielraum?
Testing untestable code
Abstrahieren du sollst!
Was sonst?
Testing untestable code
Generative Programmierung
Generative Programmierung
Testing untestable code
GeneratorGenerator
Generative Programmierung
Testing untestable code
Konfiguration(DSL)
Konfiguration(DSL)
GeneratorGenerator
Generative Programmierung
Software generieren statt programmieren
Konfiguration(DSL)
Konfiguration(DSL)
Implementierungs-komponenten
Implementierungs-komponenten GeneratorGenerator
Generative Programmierung
Testing untestable code
Konfiguration(DSL)
Konfiguration(DSL)
Implementierungs-komponenten
Implementierungs-komponenten GeneratorGenerator
ProduktProdukt
1..n
Generative Programmierung
Testing untestable code
Konfiguration(DSL)
Konfiguration(DSL)
Implementierungs-komponenten
Implementierungs-komponenten GeneratorGenerator
ApplikationApplikation
TestsTests
Testing untestable code
Generative Programmierung
Ein Frame ist eine Datenstrukturdie Wissen repräsentiert.
Testing untestable code
Eine Frame Instanz
<?phpclass Car {
private $engine;
public function __construct($engine) {$this->engine = <!{Factory}!>::
getByType($engine);}
}
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");}
}}
Testing untestable code
Nach der Generierung - Testcase
<?phpclass Car {
private $engine;
public function __construct($engine) {$this->engine = FactoryMock::
getByType($engine);}
}
Testing untestable code
Nach der Generierung - Applikation
<?phpclass Car {
private $engine;
public function __construct($engine) {$this->engine = EngineFactory::
getByType($engine);}
}
Testing untestable code
Was ist möglich?
Testing untestable code
Was ist möglich?
Extraktion von Codezeilen
Testing untestable code
Was ist möglich?
Globale Inhalte verändern
Testing untestable code
Was ist möglich?
Pre- oder Postfixes für Methoden
Testing untestable code
Wie weit sollte man gehen?
Vielen Dank!
Testing untestable code
Bildquellen
http://www.flickr.com/photos/andresrueda/3452940751/
http://www.flickr.com/photos/andresrueda/3455410635/
top related