Sollten Unit-Tests nur "funktionale" Software abdecken?

9

Wir verwenden StructureMap in einem neuen Softwareentwicklungsprojekt. Eines der Teammitglieder hat einen Komponententest implementiert, der im Wesentlichen die StructureMap- Containerkonfiguration testet . Dies geschieht durch Folgendes:

  • Zählt die Anzahl der Instanzen von Assemblys, die für Klassen in unserem Anwendungsnamespace konfiguriert sind.
  • Definiert erwartete Instanzen auf Klassenebene
  • Gibt an, dass die erwarteten Instanzen mit der Gesamtzahl der gefundenen Instanzen übereinstimmen.
  • Gibt an, dass die erwarteten Instanzen mit den im Test definierten übereinstimmen

Ein Beispiel dafür ist;

var repositories = container.GetAllInstances<IEnvironmentRepository>();
Assert.AreEqual(1, repositories .Count());
foundInstances = foundInstances + repositories .Count();

Wir haben auch "Unit-Tests" für die folgende Klasse;

public MyClass(IEnvironmentRepository environmentRepository)
        {

        }

In diesen Tests verspotten wir IEnvironmentRepository, würden es also nicht wie im Live-System aus dem Container injizieren.

Ein Kollege ignorierte den Komponententest in der Strukturkartenkonfiguration mit einem Kommentar in der Zeile "Komponententest testet nur die eigene Konfiguration". Dies war offensichtlich der Zweck des Tests und ist meiner Meinung nach vollkommen gültig. Ich habe den Typen, der den Test ignoriert hat, gebeten, die Strukturzuordnungskonfiguration für IEnvironmentRepository(wobei der Test immer noch ignoriert wird) zu entfernen und die vollständige Unit-Test-Suite auszuführen. Alle haben bestanden. Wir haben dann die Anwendung ausgeführt und sie ist umgefallen, weil die Containerkonfiguration jetzt ungültig war. Meiner Meinung nach hat dies den Wert des Tests bewiesen, mein Kollege war immer noch anderer Meinung. Er erklärte lediglich, dass wir die Konfiguration nicht testen sollten, aber ich denke, dass dies im Rahmen eines Komponententests liegt.

Also eine Reihe von Fragen;

  • Ist es ein gültiger Komponententest? Wir testen die Konfiguration unseres Containers, nicht dass die Strukturkarte funktioniert (aber ich kann die Überlappung sehen).
  • Wenn nicht, wie können Sie die Konfiguration überprüfen, ohne sie zu testen? Wie können Sie verhindern, dass jemand versehentlich eine erforderliche Codezeile löscht und eincheckt?
  • Sollte der MyClassUnit-Test die Instanz von IEnvironmentRepositoryaus dem Container auflösen und übergeben?
ChrisBint
quelle
10
9 von 10 Meinungsverschiedenheiten in Bezug auf Tests ergeben sich aus der Tatsache, dass Frameworks automatisierte Tests in all ihren Formen unterstützen, und die Benutzer möchten sich mit der Semantik befassen, ob ein bestimmter automatisierter Test ein guter und ordnungsgemäßer Komponententest ist oder nicht. Der Test, den Sie beschreiben, klingt wie ein nicht ganz einheitlicher Test, der sehr nützlich sein kann, um ihn zu haben und zu automatisieren (und beim Einchecken auszuführen) - nennen Sie ihn einfach keinen Komponententest. Fragen Sie, ob Ihr Kollege nachts besser schlafen würde, wenn der Test in einem eigenen Feature / Ordner gespeichert wäre, der klar voneinander getrennt ist.
Jeroen Mostert
2
Das ist auch meine Meinung, wahrscheinlich nützlich, und obwohl es sich nicht ausschließlich um einen Komponententest handelt, bietet es einen Mehrwert, und dies wurde bewiesen. Seine Antwort war, dass die anderen Unit-Tests dies aufgegriffen hätten, aber meiner Meinung nach würden Sie, wenn sie als strenge Unit-Tests geschrieben würden, über die Abhängigkeiten verspottet und würden daher nie wissen, ob die Konfiguration gültig ist, bis Sie sie verwendet haben.
ChrisBint
4
Ihr Kollege hat einen Punkt, an dem er sagt, dass die Konfiguration nicht getestet werden soll, da eine echte Konfiguration, die tatsächlich pro Bereitstellung variieren kann, nicht getestet werden kann / sollte - wer sagt, dass "rot" falsch ist und "blau" nicht? Der Test wäre eng an einen Aufbau gekoppelt. Eine Konfiguration, die an Code-Artefakte gebunden ist, ist jedoch eine Ausnahme, da sie nicht variiert und es eindeutig Möglichkeiten gibt, Fehler zu machen. Im Idealfall wird eine solche Konfiguration zum Zeitpunkt der Erstellung aus DRY-Metadaten generiert. Wenn dies jedoch nicht möglich ist, bietet ein Test wie dieser einen Mehrwert. Besser als ein vermeidbarer Bereitstellungsfehler.
Jeroen Mostert
2
Was Sie beschreiben, testet kein Gerät, sondern die Konfiguration einer Software eines Drittanbieters. Es ist fantastisch nützlich , Tests zu haben, die diese Dinge testen, aber es handelt sich um Integrationstests, nicht um Komponententests, und die Trennung dort kann die Wurzel der Meinungsverschiedenheit sein.
Phoshi
3
@ ChrisBint Meine Güte, nein, ich habe selbst eine Reihe von Containertests geschrieben. Sie haben viel Wert, sie sind einfach keine Unit-Tests. Das ist in Ordnung, Integrationstests sind äußerst wertvoll, um Dinge zu erfassen, die Unit-Tests nicht können .
Phoshi

Antworten:

13

Dies ist ein absolut gültiger automatisierter Test. Ich nenne sie "Architekturtests", da sie die Solidität der Skelettkomponenten Ihrer Codebasis überprüfen.

Kann der IoC-Container alle Objektbäume in der Anwendung auflösen und zusammenstellen? Kann der Auto Mapper alle registrierten Objekte ohne Fehler zuordnen? Bezieht sich die zentrale Schicht in einer Zwiebelarchitektur nicht auf etwas Äußeres?

Diese Tests können Ihnen viel Zeit sparen, wenn sich ein Konfigurationsfehler einschleicht, indem Sie auf den genauen Schuldigen hinweisen. Gute Frameworks geben Ihnen sehr genaue Fehlermeldungen darüber, was falsch ist, und Sie erhalten sie, sobald Sie die Tests ausführen (idealerweise kontinuierlich), anstatt sie mit etwas Glück tief in einem Laufzeit-Stack-Trace zu vergraben.

Ob es sich um Unit-Tests handelt ... wahrscheinlich nicht, aber sie arbeiten größtenteils immer noch im Speicher und laufen ziemlich schnell. Andererseits, ich weiß nicht, ist es nicht so, als gäbe es eine allgemein akzeptierte Definition von Unit Test.

guillaume31
quelle
Ironischerweise habe ich es meinem Kollegen so ziemlich erklärt, und selbst bei der Validierung (eine der Containerinstanzen löschen und die Anwendung ausführen) sah er immer noch keinen Wert. Ich verstehe, dass jeder seine eigene Meinung hat, und ich habe meine geäußert;) Ich liebe den Begriff "Architekturtest", das werde ich stehlen!
ChrisBint
6

Das Problem bei einem solchen Test, bei dem die Interna des Programms getestet werden und nicht eine Anforderung. Ist das, dass der Test fehlschlagen kann, auch wenn das Programm wie erforderlich funktioniert.

Wenn Sie in Ihrem Fall das Container-Setup ändern und möglicherweise eine neue Abhängigkeit haben, die injiziert werden muss, brechen Sie Ihren Test ab.

Wenn Sie die zusätzliche Abhängigkeitsanforderung hinzufügen, aber vergessen, sie dem Container hinzuzufügen, und den Containertest ändern. Alles wird vergehen, aber Ihr Programm wird abstürzen.

Ein besserer automatisierter Test wäre, das Programm zu starten und zu prüfen, ob es abstürzt.

Sie sollten diese Fehlertypen bei Integrations- oder UI-Tests abfangen, auch wenn sie durch die Komponententests fallen.

Trotzdem ist die zunehmende Komplexität der Containereinrichtung ein Ärgernis. Vielleicht lohnen sich einige "schlechte" Tests.

Ewan
quelle
1

Unit-Tests Testcode. Alles andere ist "anderes" automatisiertes Testen - nennen Sie es so, wie Sie wollen. Sie scheinen hier die Konfiguration zu testen. Wenn sich die Konfiguration je nach Umgebung ändern kann, gehört sie nicht zu einem Komponententest. Fügen Sie möglicherweise ein Testattribut hinzu, um anzuzeigen, dass der Test von einem anderen Typ als die anderen Tests ist.

Robbie Dee
quelle
Die Konfiguration ist statisch und wird nicht von der Umgebung gesteuert. Alle in der Konfiguration vorhandenen Klassen werden in allen Umgebungen auf dieselbe Weise verwendet. Ja, die Anzahl der Instanzen , die in der Config sein könnten , dass die Anzahl der Instanzen in der Config übereinstimmen, das ist Teil des Tests. Wie mein Beispiel gezeigt hat, konnten die anderen Komponententests durch Entfernen von IEnvironmentRepository bestanden werden. Der spezifische Containertest wäre bei 2 Asserts fehlgeschlagen. 1 - Die Gesamtzahl der möglichen Instanzdeklarationen stimmte nicht überein, und 2 - Die spezifische Anzahl der Instanzen von IEnvironmentRepository stimmte nicht überein.
ChrisBint
1
Die Richtigkeit des Containers wird vom Codierer festgelegt. Die Tatsache, dass sich sowohl der zu testende Code als auch der Test selbst für jede Änderung ändern müssen, lässt sofort Alarmglocken läuten. DI ist ein Mittel zum Zweck und nicht der Zweck an sich. Es ist durchaus möglich, Code in einem DI-Stil ohne Strukturkarte zu schreiben, daher ist es meiner Ansicht nach kein echter Unit-Test. Der Container muss natürlich bewiesen werden, aber die Wirksamkeit mit automatisierten Tests scheint angesichts der begrenzten Informationen, die hier bereitgestellt werden, etwas umstritten zu sein.
Robbie Dee
2
Unit-Tests dauerten 10 Minuten. Die Bereitstellung kann über eine Stunde dauern.
ChrisBint
1
Ein Teil des Komponententests überprüft speziell das Vorhandensein einer einzelnen Zeile in der Konfiguration und ist sich nicht sicher, wie dies nicht isolierter hätte sein können. Der allgemeinen Zählung konnte ich zustimmen.
ChrisBint
1
Dann könnten einige Kilometer in ihnen stecken - ein Urteilsspruch für Sie wirklich. Sie sollten jedoch entweder physisch oder über ein Attribut getrennt werden.
Robbie Dee
0

Die Verantwortung des Abhängigkeitsinjektionsbehälters besteht darin , verschiedene Module in einer Arbeitsanwendung zu kleben .

Wenn Sie automatisierte Tests für Ihre Anwendung schreiben, sollten Sie nur wenige "Integrations- (oder Akzeptanz-) Tests haben, die Tests" von Ende zu Ende "ausführen, mit denen die gesamte Pipeline Ihrer Anwendung getestet wird , damit alle an einem bestimmten Testfall beteiligten Module zusammengeklebt werden richtig .

Diese Integrationstests schlagen also fehl, wenn der Abhängigkeitsinjektionscontainer nicht ordnungsgemäß konfiguriert wurde. Dies macht Unit-Tests für den Container selbst unbrauchbar, da der Integrationstest mögliche Fehler in der Containerkonfiguration aufzeigen sollte.

Sie müssen nicht alle möglichen Testfälle in Integrationstests abdecken, sondern nur einen Testfall pro Feature, der den gesamten Weg von der Benutzeroberfläche zur Datenbank abdeckt.

Wenn Integrationstestfälle die Instanziierung einer bestimmten Abhängigkeit nicht abdecken, fügen Sie einfach eine solche hinzu.

Mit Integrationstests können Sie Container frei wechseln, ohne Unit-Tests für ihre Konfiguration neu schreiben zu müssen.

Fabio
quelle
0

IMO, die Antworten sind:

  1. Ist es ein gültiger Komponententest? Wir testen die Konfiguration unseres Containers, nicht dass die Strukturkarte funktioniert (aber ich kann die Überlappung sehen).

    • Es ist ein gültiger Komponententest für die Strukturkarte , nicht für Ihr Projekt, da ein einheitlicher Test einen bestimmten Code testet und bei Bedarf alle Abhängigkeiten verspottet, um die implementierte Logik zu testen. Die Konfigurationslogik innerhalb StructureMap implementiert, damit diese Bibliothek muss auch geprüft werden und müssen enthalten Unit - Tests wie diese Sie erwähnt haben , und mehr: es sollte Hunderte von Tests wie diese, dynamisch spöttischen mehrere Konfigurationen zur Laufzeit und zu testen , um zu sehen enthalten , wenn die Container verhält sich wie es sollte.
  2. Wenn nicht, wie können Sie die Konfiguration überprüfen, ohne sie zu testen? Wie können Sie verhindern, dass jemand versehentlich eine erforderliche Codezeile löscht und eincheckt?

    • Sie können die Konfiguration manuell in der erforderlichen Umgebung testen und eine Automatisierung dafür erstellen (automatisierter Test), die die spezifische Konfiguration testet, die Sie benötigen (Sie müssen sich zur Laufzeit nicht verspotten).
  3. Sollte der MyClass-Komponententest die Instanz von IEnvironmentRepository aus dem Container auflösen und übergeben?

    • Nein, dies ist ein perfekter Komponententest, da Sie die Abhängigkeit verspotten und die MyClass-Logik isoliert testen.
Emerson Cardoso
quelle
-1

UnitTest überprüft das gewünschte Verhalten einer Einheit bei der Trennung .

Das bedeutet , jede Art von Konfiguration ist nicht in den Anwendungsbereich von Unittests .

Trotzdem sollten Sie automatisierte Tests für Ihre Konfigurationen haben, aber dies sind keine UnitTests ...

Timothy Truckle
quelle
Woher bekommen Sie die Definition von Einheiten?
ChrisBint
Ich mag den von Roy Osherove in Die Kunst des Unittesting : Eine Einheit ist ein Teil des (Produktions-) Codes, der den gleichen Grund zur Änderung hat. In meiner Welt reicht dies normalerweise von einer einzelnen Klasse bis zu drei oder fünf ...
Timothy Truckle
Dies ist der Produktionscode, der getestet wird.
ChrisBint
Ich wollte nur die Nitpicker ablenken und nicht erwarten, dass es auch umgekehrt funktioniert ...; o)
Timothy Truckle