Wie schreibt man Tests für Code, der von konkreten externen Implementierungen abhängt, die nicht verspottet werden können?

17

Hintergrund: Ich denke darüber nach, meinen Mitarbeitern das Konzept der Komponententests vorzustellen, indem ich einige für ein Modul erstelle, an dem ich gearbeitet habe. Die Anforderungen haben sich in letzter Zeit geändert und erfordern einige weitere Abstraktionen / Interaktionen. Daher scheint es eine gute Möglichkeit zu sein, eine Reihe von Tests zu entwickeln, die "beweisen", dass sie funktionieren, ohne manuell in der Anwendung herumzustöbern.

Das Problem ist jedoch, dass das Modul auf nicht nachahmbaren externen Faktoren beruht, nämlich PDFs und XSL. Grundsätzlich lese ich XML aus der Datenbank und wende eine XSL-Transformation darauf an. Anschließend konvertiere ich es mithilfe einer Bibliothek namens ABCPDF in ein PDF. Dieses PDF wird dann mit einem anderen PDF zusammengeführt, das auf einer statischen Vorlage basiert. Ich weiß, dass ich das XML testen und sicherstellen kann, dass die Werte korrekt sind, aber viele der potenziellen Fehler und Probleme hängen mit der tatsächlichen Anzeige des fertigen Dokuments zusammen - z befindet sich in Bezug auf das Dokument, etc. Ist es sogar möglich, diese Dinge zu testen (ich erkenne, dass dies wahrscheinlich Integrationstests sind oder .. die dritte Art von Test, dessen Name ich vergesse [keine Akzeptanztests, die andere Art], und keine Einheit Tests), da ich meines Wissens nicht in der Lage bin, eine PDF-Datei zu verspotten, ohne sie erst zu erstellen, dann zurückzulesen oder eine HTML-Zeichenfolge (dh transformiertes XML) zu erstellen und von Hand zu analysieren, um festzustellen, ob bestimmte Tabellenzellen in vorhanden sind Beziehung zu anderen Tabellenzellen.

Sollte ich mich in einer solchen Situation nur auf Komponententests konzentrieren, um sicherzustellen, dass die Informationen korrekt sind und ich das PDF erstellen oder zusammenführen kann, oder was auch immer, und auf manuelle Tests für die tatsächlichen Anzeigeprobleme zurückgreifen?

Wayne Molina
quelle
6
"nicht verspottbare externe Faktoren" ist ein Hinweis darauf, dass Sie nicht in erster Linie Unit- Tests durchführen. Das bedeutet Integrationstests . Was willst du machen Unit-Test Ihres Codes oder Integrationstest dieses Composite- Dings? Bitte wählen Sie das eine oder andere aus, da es schwierig ist, über beide gleichzeitig zu sprechen.
S.Lott
2
Ich kaufe nicht "unmockable". Ich werde akzeptieren, "dass ich nicht weiß, wie ich verspotten soll", was nur bedeutet, dass Ihre eigentliche Frage "Wie verspotte ich es?" Ist.
Rein Henrichs
Wahrscheinlich :) Ich bin mit dem Verspotten des verwendeten XML vertraut, aber nicht mit dem Verspotten eines tatsächlichen PDF- oder HTML-Dokuments, bei dem es auf die Formatierung ankommt.
Wayne Molina
1
Ich denke, Sie meinen "funktionale" (Anwendung Ende zu Ende) oder "System" (mehrere Anwendungen Ende zu Ende) Tests
Gary Rowe
@ Gary - Ja, funktional war das Wort. Ich erinnere mich jetzt daran, wie ich Rails gelernt habe: Unit-Tests-Modelle, Funktionstests-Controller, Integrationstests alles.
Wayne Molina

Antworten:

13

Testen Sie die Funktion, nicht das Gerät

Verwenden Sie bekannte XML-Eingaben, um eine PDF-Datei auszugeben, und überprüfen Sie manuell (und sorgfältig), ob sie korrekt ist. Speichern Sie es dann als Referenz.

Zukünftige Tests, die dieselben XML-Eingaben verwenden, können einen Binärdateivergleich mit der Referenz durchführen.

Wenn ein Vergleich auf Dateiebene nicht zufriedenstellend ist, zeigen Sie die PDF-Datei am Ende des Tests an und machen Sie Screenshots. Lassen Sie dann den automatisierten Test mit den Referenz-Screenshots vergleichen.

Steven A. Lowe
quelle
+1, weil Sie nur am Endergebnis auf dieser Ebene interessiert sind. Wenn Sie die Implementierung dahingehend ändern, wie Sie das PDF erhalten, sollten Sie Ihren Funktionstest nicht ändern müssen.
Gary Rowe
2
+1 für eine gute Beratung, das tun wir in unserem aktuellen Projekt. Für den PDF-Vergleich haben wir ein benutzerdefiniertes Toolset erstellt, mit dem sich ändernde Teile in den Dokumenten, z. B. Zeitstempel, weglassen lassen. Vorsichtsmaßnahme: Das Wechseln zu einer anderen (Version des) PDF-Renderers kann geringfügige Änderungen im Layout verursachen und einen direkten binären Vergleich mit Signalhaufen falsch positiver Ergebnisse bewirken.
Péter Török
5

Normalerweise abstrahieren Sie in einem solchen Fall alles, was Sie nicht hinter einer Implementierung testen können, die Sie mit einer Schnittstelle verwenden können. Ich mache einfach so was dummes wie PDF Builder, weil das vernünftig erscheint.

public class PdfBuilder : IPdfBuilder
{
  public byte[] BuildPdf(...)
  {
    // actual untestable code here
  }
}

public interface IPdfBuilder
{
  byte[] BuildPdf(...);
}

Anschließend können Sie den IPdfBuilder in Ihren Tests verspotten, um zu tun, was Sie wollen. Dies bedeutet häufig, dass Sie einen IoC-Container verwenden müssen ( /programming/871405/why-do--need-an-ioc-container-as-opposed-to-straightforward-di-code und /programming/21288/which-net-dependency-injection-frameworks-are-worth-looking-into als Ausgangspunkt), wenn Sie gerade keinen verwenden.

Und Tests, die keine Komponententests sind, werden oft als Integrationstests bezeichnet. Komplizierte Integrationstests lohnen sich oft nicht vollständig. Sie abstrahieren diesen Teil und reduzieren den Umfang der Geschäftslogik in dieser Abstraktion, damit Sie ihn in einem Komponententest testen können.

Lassen Sie mich wissen, wenn dies nicht ganz klar ist.

Travis
quelle
+1 zum Ausblenden von nicht testbarem Code. Anschließend können Sie manuelle Tests durchführen, bis Sie herausgefunden haben, was diese Schnittstelle passieren muss, um das richtige Ergebnis zu erzielen , und einen Komponententest durchführen , der ordnungsgemäß generiert wird, um Ihre Regressionseinheitentests zu erhalten.
Ethel Evans
1

Ich habe vor einiger Zeit etwas sehr ähnliches gebaut und nur grundlegende visuelle Tests verwendet. Das Testen muss nicht automatisiert werden, sodass es nichts auszusetzen hat, nur nach einem erwarteten Ergebnis zu suchen (offensichtlich in einer Vielzahl von Situationen, die vorbestimmt sind). Oft ist ein Bild tausend Tests wert, wenn es um visuelle Aspekte geht . Ich benutze ausgiebig automatisierte Komponententests, aber ich denke, einige Leute können sich ein wenig mitreißen lassen, wenn sie in GUI-Tests einsteigen, oder irgendetwas visuelles IMHO. Mit bestimmten Produkten erkenne ich, dass dieser "gut genug" Ansatz nicht ausreicht, also YMMV.

Ich wäre jedoch ein bisschen besorgt über die nicht verspottbaren externen Effekte. Dies kann ein Zeichen für eine enge Kopplung sein, die als Faustregel zu vermeiden ist, aber ohne weitere Details werde ich nicht zu viel über Ihren Code spekulieren.

Morgan Herlocker
quelle
Es ist sehr eng miteinander verbunden, aber das ist ein Bereich, den ich nicht beheben kann, da es kein Buy-in gibt, um es locker miteinander zu verbinden, und keine Ressourcen für das Refactoring vorgesehen sind (aber das ist eine ganz andere Reihe von Problemen).
Wayne Molina