Das Testen von Code im Allgemeinen ist nicht einfach. Wenn es so wäre, hätten wir das alles schon vor langer Zeit gemacht und erst in den letzten 10 bis 15 Jahren so viel daraus gemacht. Eine der größten Schwierigkeiten bestand immer darin, zu bestimmen, wie Code getestet werden soll, der zusammenhängend, gut faktorisiert und testbar ist, ohne die Kapselung zu unterbrechen. Das BDD-Prinzip schlägt vor, dass wir uns fast ausschließlich auf das Verhalten konzentrieren, und scheint in gewisser Weise darauf hinzudeuten, dass Sie sich nicht wirklich so sehr um die inneren Details kümmern müssen, aber dies kann es oft schwierig machen, die Dinge zu testen, wenn es welche gibt Viele private Methoden, die auf sehr versteckte Weise "Sachen" machen, da dies die Gesamtkomplexität Ihres Tests erhöhen kann, um alle möglichen Ergebnisse auf einer öffentlicheren Ebene zu behandeln.
Spott kann bis zu einem gewissen Grad helfen, ist aber wiederum ziemlich extern ausgerichtet. Die Abhängigkeitsinjektion kann auch sehr gut funktionieren, wiederum mit Mocks oder Test-Doubles. Dies kann jedoch auch erfordern, dass Sie Elemente entweder über eine Schnittstelle oder direkt verfügbar machen, die Sie sonst möglicherweise lieber versteckt hätten - dies gilt insbesondere, wenn Sie dies wünschen Haben Sie ein gutes paranoides Sicherheitsniveau für bestimmte Klassen in Ihrem System.
Für mich ist die Jury immer noch unschlüssig, ob Sie Ihre Klassen so gestalten sollen, dass sie leichter zu testen sind. Dies kann zu Problemen führen, wenn Sie neue Tests bereitstellen müssen, während der Legacy-Code beibehalten wird. Ich akzeptiere, dass Sie in der Lage sein sollten, absolut alles in einem System zu testen, aber ich mag es nicht, die privaten Interna einer Klasse - auch indirekt - freizulegen, nur damit ich einen Test für sie schreiben kann.
Für mich war die Lösung immer, einen ziemlich pragmatischen Ansatz zu wählen und eine Reihe von Techniken zu kombinieren, um sie an die jeweilige Situation anzupassen. Ich verwende viele geerbte Testdoppel, um innere Eigenschaften und Verhaltensweisen für meine Tests aufzudecken. Ich verspotte alles, was an meine Klassen angehängt werden kann, und wo dies die Sicherheit meiner Klassen nicht beeinträchtigt, werde ich ein Mittel bereitstellen, um Verhaltensweisen zum Testen zu überschreiben oder zu injizieren. Ich werde sogar in Betracht ziehen, eine ereignisgesteuerte Schnittstelle bereitzustellen, wenn dies dazu beiträgt, die Fähigkeit zum Testen von Code zu verbessern
Wo ich einen "nicht testbaren" Code finde , schaue ich nach, ob ich ihn umgestalten kann, um die Dinge testbarer zu machen. Wo viel privater Code hinter den Kulissen versteckt ist, finden Sie oft neue Klassen, die darauf warten, ausgebrochen zu werden. Diese Klassen können intern verwendet werden, können jedoch häufig unabhängig voneinander mit weniger privatem Verhalten und anschließend häufig weniger Zugriffs- und Komplexitätsebenen getestet werden. Eine Sache, die ich jedoch vermeiden möchte, ist das Schreiben von Produktionscode mit integriertem Testcode. Es kann verlockend sein, " Testfahnen " zu erstellen if testing then ...
, die dazu führen, dass solche Schrecken eingeschlossen werden , die auf ein Testproblem hinweisen, das nicht vollständig dekonstruiert und unvollständig gelöst ist.
Es könnte hilfreich sein , das Buch xUnit Test Patterns von Gerard Meszaros zu lesen , in dem all diese Dinge ausführlicher behandelt werden, als ich hier behandeln kann. Ich mache wahrscheinlich nicht alles, was er vorschlägt, aber es hilft, einige der schwierigeren Testsituationen zu klären. Letztendlich möchten Sie in der Lage sein, Ihre Testanforderungen zu erfüllen, während Sie weiterhin Ihre bevorzugten Designs anwenden, und es hilft, alle Optionen besser zu verstehen, um besser entscheiden zu können, wo Sie möglicherweise Kompromisse eingehen müssen.