Ich hatte kürzlich meine Abschlussprüfung für einen Software-Engineering-Kurs für mein Masterstudium und eine der Fragen in der Prüfung war die folgende:
Unit Testing is considered:
a. White-box Testing
b. Black-box Testing
c. Either
In meiner 7-jährigen Erfahrung in der Softwareentwicklung haben Unit-Tests immer einen White-Box-Ansatz gewählt. Der Tester hatte beim Schreiben der Tests immer umfassende Kenntnisse über die Implementierung des Geräts. Black-Box-Tests wurden immer später in Form von Integrations-, System- und Abnahmetests durchgeführt.
Die richtige Antwort auf die Prüfung (laut Professor) ist jedoch, dass Unit-Tests entweder White- oder Black-Box-Tests sein können.
Ich habe einige Nachforschungen angestellt, und es scheint, dass in vielen Fällen "Black-Box-Unit-Tests" verwendet werden, um einen Test-First-Ansatz zu beschreiben, bei dem die Unit-Tests vor dem Code geschrieben werden. Meiner Meinung nach handelt es sich jedoch immer noch um White-Box-Tests. Obwohl die Implementierung noch nicht existiert, hat jeder, der den Test schreibt, im Allgemeinen eine ziemlich gute Vorstellung davon, wie der Quellcode implementiert werden soll.
Kann mir bitte jemand erklären, wie Black-Box-Unit-Tests funktionieren (wenn es wirklich so ist) und wie sie sich von White-Box-Unit-Tests unterscheiden?
quelle
While the implementation does not yet exist, whoever is writing the test generally has a pretty good idea about how the source code is going to be implemented.
- Ja, aber der Test selbst nicht. White-Box-Test bedeutet, etwas innerhalb der Methode oder Klasse zu testen, beispielsweise den Wert einer Variablen. Dies bedeutet nicht, dass der Testschreiber weiß, wie der zu testende Code aussieht.Antworten:
Ihr Professor hat Recht: Unit-Tests können entweder Black-Box- oder White-Box-Tests sein. Der Unterschied besteht weniger darin, was der Tester weiß, sondern vielmehr darin, wie Sie Testfälle generieren.
Beim Black-Box-Test sehen Sie sich nur die Schnittstelle und (falls vorhanden) die Spezifikation für eine Komponente an. Wenn eine Funktion eine Signatur hat
int foo(int a, int b)
, kann ich sofort einige Testfälle generieren, indem ich interessante Ganzzahlen teste: Null, Eins, Minus Eins, mehrstellige Zahlen, INT_MAX, INT_MAX - 1 und so weiter. Black-Box-Tests sind großartig, weil sie unabhängig von der Implementierung sind. Sie könnten aber auch wichtige Fälle übersehen.Bei einem White-Box-Test betrachte ich die Implementierung, dh den Quellcode, und generiere daraus Testfälle. Zum Beispiel möchte ich vielleicht eine 100% ige Pfadabdeckung für eine Funktion erreichen. Ich wähle dann Eingabewerte, damit alle Pfade genommen werden. White-Box-Tests sind großartig, da sie einen Teil des Codes mit weitaus mehr Sicherheit als Black-Box-Tests ausführlich ausführen können. Möglicherweise testen sie jedoch nur Implementierungsdetails, kein wirklich wichtiges Verhalten. In einigen Fällen sind sie eindeutig Zeitverschwendung.
Da aus der Implementierung ein White-Box-Test abgeleitet wird, kann dieser erst danach geschrieben werden. Ein Black-Box-Test wird aus dem Design / der Schnittstelle / der Spezifikation abgeleitet und kann daher vor oder nach der Implementierung geschrieben werden. TDD ist weder eindeutig Black-Box noch White-Box. Da das gesamte Verhalten zuerst durch einen Test ausgedrückt wird und dann der minimale Code für dieses Verhalten implementiert wird, führt TDD zu ähnlichen Testfällen wie ein White-Box-Test. Wenn wir uns jedoch den Informationsfluss ansehen, werden TDD-Tests nicht aus dem Quellcode abgeleitet, sondern aus externen Anforderungen. Daher ist TDD eher Black-Box-ähnlich.
quelle
Wenn Sie eine testgetriebene Entwicklung durchführen, sollten theoretisch alle Unit-Tests Black-Box sein. Dies ist Ihr "Test-First-Ansatz". Sie schreiben den Vertrag (Schnittstelle), schreiben die Tests für diesen Vertrag und dann wird der Vertrag von der Implementierung erfüllt. Der Test weiß daher nichts über die Implementierung und sollte auch nichts wissen.
Was testen Sie schließlich, wenn Sie einen Test schreiben? Öffentliche Methoden / Funktionen.
Wenn Sie die Schnittstelle für eine Klasse schreiben und dann die Tests schreiben und dann von einem Bus angefahren werden, sollte der Typ, der die Klasse schreibt, während Sie im Krankenhaus sind, dies über Ihre Schnittstelle tun können, oder? Er sollte es nicht wegwerfen und seine eigene Schnittstelle und Tests schreiben müssen.
Dies fällt etwas auseinander, wenn Sie etwas verspotten müssen, von dem die Implementierung abhängt. Wenn Sie sich jedoch in einer Situation befinden, in der Sie etwas verspotten, das niemals öffentlich zugänglich gemacht wird, haben Sie einen Fehler gemacht, und Sie müssen es tun siehe Dependency Injection et al . Daher würde ich argumentieren, dass White-Box-Unit-Tests, nicht Schwarz, die Ausnahme sein sollten.
Betrachten Sie "Testen auf der Toilette - Testverhalten nicht implementiert" , wobei die Implementierung einer Klasse geändert wird, die Tests jedoch weiterhin gültig sein sollten.
Wenn Sie jedoch sicherstellen müssen, dass Ihre Codeabdeckung aktiv ist (dh sicherstellen, dass alle bedingten Pfade innerhalb der Implementierung getestet werden), müssen Sie unbedingt einen White-Box-Unit-Test durchführen, da Sie nur so wissen können, was Sie tun Pfade sind durch Betrachten der Pfade in der Implementierung.
quelle
If you were to write the interface for a class, and then write the tests, and then you get hit by a bus, the guy who writes the class while you're in hospital should be able to do so from your interface, right?
-- Nicht genau. Die meisten API-Verträge geben nur Methodensignaturen an, nicht Semantik oder Verhalten.Ich würde argumentieren, dass alle gut geschriebenen Unit-Tests von Natur aus "Black Box" sind. Sicher, ich habe vielleicht eine Implementierung im Sinn, wenn ich den Test schreibe, aber diese Implementierung kann sich ändern, wenn ich umgestalte. Daher sollte der Test während des Tests nur öffentliche APIs verwenden, um die Funktionalität zu testen, nicht die Implementierung. Die Implementierungsdetails sind nicht wichtig, daher werden die Black-Box-Tests durchgeführt.
Wenn ich Tests schreibe, die auf interne oder private Aspekte des zu testenden Geräts zugreifen, teste ich die Implementierungsdetails: Ich teste White Box. Ich schreibe aber auch spröde Tests, die leicht brechen können, wenn die Implementierung geändert wird. Solche White-Box-Tests sind daher eine schlechte Idee und sollten vermieden werden.
Fazit: Wenn Sie einen White-Box-Test mit Unit-Tests durchführen, haben Sie schlecht konstruierte Tests. Nur Backbox-Test mit diesen Unit-Tests. Ihr Professor hat Recht: Es kann beides sein. Aber nur wenn schlecht gemacht.
quelle
Ich war gerade dabei, Unit-Tests zu schreiben, die Black-Box-Tests durchführen. Das heißt, ich teste öffentliche Methoden in einer Klasse und impliziere die Logik zum Testen der Ergebnisse in den privaten Methoden, die sie aufrufen.
Ich tue dies, indem ich Eingaben in die öffentliche Methode ändere, die Unit-getestet wird, und erwartete Ausgaben teste, die durch Logik in den unterstützenden privaten Methoden bestimmt oder mutiert werden, über deren Implementierung meine "Unit-Tests" nichts wissen müssen.
Es hindert Sie also nichts daran, Black-Box-Tests für Komponententests durchzuführen, und die Tests werden unterbrochen, wenn jemand mit der Implementierung der verborgenen unterstützenden Logik in Konflikt gerät. Tatsächlich scheint dies ein überlegener, effizienterer Ansatz zu sein, als wenn eine White-Box-Einheit alles in einer Klasse testet. Ich bin bei dem Professor.
quelle