Nachdem der Entwicklungsprozess automatisiert, die Test-Umgebung aufgesetzt und die ersten Tests für neue Klassen entwickelt wurden, stellt sich die Frage, was mit dem bereits bestehenden Code geschehen soll. Der Code ist teilweise sehr alt, hat viele Abhängigkeiten und scheint untestbar zu sein. Aufgrund des Alters handelt es sich evtl. sogar um Code, der von Entwicklern geschrieben wurde, die schon seit langer Zeit nicht mehr im Unternehmen tätig sind. Niemand traut sich wirklich an den Code ran und Refactoring-Maßnahmen werden vermieden.
Wie fängt man an?
Es handelt sich um einen riesigen Berg an Code, für den Tests geschrieben werden müssen. Es geht nicht darum, dass sich ein Entwickler 2 Monate einschließt und alle fehlenden Tests nachpflegt. Wichtig ist, dass die Entwicklung der Tests sukzessive und von allen Entwicklern durchgeführt wird. Man startet am besten mit ein paar einfachen Klassen und tastet sich langsam am die komplexeren Klassen heran. Es müssen auch nicht alle Methoden einer Klasse in einem Zug durch Tests abgedeckt werden. Um die Sukzessivität zu erreichen, könnte man erneut die Pfadfinder-Regel einsetzen: Muss ein Entwickler etwas am alten Code ändern, muss er die entsprechende(n) Methode(n) vorerst durch Tests abdecken.
Abhängigkeiten auflösen
Alter Code enthält oft unzählige Abhängigkeiten zu anderen Klassen, Datenbanken und/oder dem Dateisystem. Diese Abhängigkeiten stören bei der Entwicklung von Tests und sollten somit mittels Refactoring aufgelöst werden. An dieser Stelle stehen wir jedoch vor einem Problem:
- Bevor wir Refactoring-Maßnahmen durchführen, benötigen wir Tests.
- Um Tests zu schreiben, müssen wir den Code erst refactoren.
Man kann den bestehenden Code also nicht anpassen, um ihn testbar zu machen. Um dieses Problem zu lösen, gibt es unterschiedliche Herangehensweisen:
- Wenn man Glück hat, werden die Abhängigkeiten bereits via Dependency Injection in die Klassen injiziert. Ist dies der Fall, kann die Abhängigkeit auf ein Interface umgestellt werden, sodass für den Test ein Mock-Objekt entwickelt und injiziert werden kann.
- Verwalten die Klassen eigenständig ihre Abhängigkeiten (keine Einsatz von DI), wird es ein wenig umständlicher. Statt die Abhängigkeiten herauszulösen und durch Mock-Objekte zu ersetzen, kann von den bestehenden Klassen abgeleitet werden, um zu mockende Methoden für den Test zu überschreiben. Statt die Klasse selbst wird dann die Ableitung der Klasse getestet, in der alle irrelevanten Methoden überschrieben („gemockt“) werden.
Was man nicht tun sollte
Werden Tests für bestehenden Code entwickelt, passiert es häufig mal, dass Fehler entdeckt werden. Die Fehler sollten jedoch nicht direkt korrigiert werden, um die Fehlerkorrektur nicht mit der Test-Entwicklung zu vermischen. Der Test sollte erstmal den falschen Code testen. Erst im Anschluss wird im Rahmen einer separaten Änderung der Fehler korrigiert. Dies kann dann durch den zuvor entwickelten Test sogar testgetrieben erfolgen.
Fazit
Die Entwicklung von Tests für Bestands-Code ist deutlich komplexer als die Entwicklung von Test für neuen Code. Dennoch muss in einem gewissen Maß sichergestellt werden, dass der alte Code nach Quellcode-Änderungen weiterhin funktioniert. Wenn man die Pfadfinder-Regel anwendet und stetig Tests für alten Code hinzufügt, entsteht nach einiger Zeit ein Bestand an Tests, der einem dabei unterstützt, auch mal Refactoring-Maßnahmen am alten Code vorzunehmen. Auch hier gilt: Man muss einfach anfangen und es sukzessive fortführen.
0 Kommentare