Wie schreibt man Komponententests für Funktionen, die auf dynamischen Daten beruhen?

8

Nehmen wir an, Sie haben eine Website, die eine Funktion zum Abrufen von Daten aus der Datenbank verwendet und das Ergebnis zur Anzeige / Analyse / etc ... zurückgibt.

Da die Daten, die aus der Datenbank abgerufen werden, dynamisch sind und möglicherweise jede Sekunde des Tages geändert werden können, wie schreibt man einen Komponententest für diese Funktion richtig?

Nehmen wir an, die Funktion soll ein Array von Ergebnissen zurückgeben. Offensichtlich könnte ein Komponententest prüfen, ob ein Array zurückgegeben wird oder nicht. Was aber passiert, wenn der Inhalt des Arrays aufgrund einer falsch geschriebenen MySQL-Abfrage nicht korrekt ist? Die Größe des Arrays könnte Null sein oder der Inhalt des Arrays könnte falsch sein. Da der Unit Test auf sich ständig ändernde Daten angewiesen ist, weiß er, was richtig ist und was nicht? Wären Aufrufe an die Datenbank aus dem Unit Test selbst notwendig, also gibt es etwas, mit dem man es vergleichen kann?

Wie schreibt man einen Komponententest für Funktionen, die auf dynamischen Daten beruhen, richtig?

    
Jake Wilson 23.04.2012, 20:50
quelle

6 Antworten

7

Unit-Tests sollten in ihrer idealen Form nur eine Sache testen. In diesem Fall testen Sie zwei Dinge:

  1. die Logik Ihrer Funktion
  2. der Datenbankabruf

Also würde ich den folgenden Refactor vorschlagen:

  1. Verschieben Sie die Datenbankabruflogik in eine separate Funktion
  2. Lassen Sie die Funktion, die Sie testen möchten, diese andere Funktion aufrufen
  3. Verstecken Sie die Funktion, die Daten zurückgibt, damit Sie nur die Logik Ihrer App testen können
  4. Wenn es sinnvoll ist (wenn Sie nur auf eine andere Bibliothek angewiesen sind, dann hoffentlich, dass lib bereits Tests enthält), schreiben Sie einen Komponententest für die dynamische Abruffunktion, wo Sie keine spezifischen Tests durchführen können, aber können kann die Struktur und die Angemessenheit der zurückgegebenen Daten testen (z. B. hat es alle Felder gesetzt und ist eine Zeit innerhalb von 5 Sekunden von jetzt an).

Außerdem ist es in der Regel eine gute Idee, Komponententests in einer Testumgebung auszuführen, in der Sie vollständige Kontrolle darüber haben, was in der Datenbank gespeichert ist. Sie möchten diese nicht mit Produktionsdaten ausführen.

    
Ben Taitelbaum 23.04.2012, 20:56
quelle
1

Wenn Ihre Funktion etwas Interessantes außer dem Herausziehen der Daten aus der Datenbank tut, sollten Sie den Abruf in eine andere Funktion extrahieren und sich über sie lustig machen, damit Sie den Rest testen können.

Damit haben Sie immer noch die Aufgabe, den Datenbankzugriff zu testen. Sie können nicht wirklich einen Komponententest dafür machen, weil das definitionsgemäß nicht auf irgendeine db zugreifen würde und Sie könnten nur testen, ob es die sql-Anweisung, die Sie denken, sollte, aber nicht, wenn die sql-Anweisung tatsächlich funktioniert.

Sie brauchen also eine Datenbank

Sie haben verschiedene Optionen:

1) Erstellen Sie eine feste Datenbank für solche Tests, die durch die Tests nicht geändert wird.

Pro: Konzeptionell einfach Con: schwer zu pflegen. Tests werden voneinander abhängig, da sie auf denselben Daten beruhen. Keine Möglichkeit, Dinge zu testen, die Aktualisierungen, Einfügungen oder Löschungen (geschweige denn DDL) durchführen

2) Erstellen Sie während des Tests eine Datenbank. Jetzt haben Sie zwei Probleme: die Datenbank für den Test einrichten und mit Daten füllen.

Einrichten:

1) einen Datenbankserver laufen lassen, mit einem Benutzer / Schema / Datenbank für jeden, der Tests durchführen muss (mindestens devs + ci-server). Das Schema kann mit Dingen wie Hibernate oder den Skripten erstellt werden, die Sie für die Bereitstellung verwenden.

Funktioniert gut, aber treibt altmodische DBAs verrückt. Die Anwendung darf nicht vom Schemanamen abhängen. Sie werden auch auf Probleme stoßen, wenn Sie mehr als ein von der App verwendetes Schema haben. Diese Einrichtung ist ziemlich langsam. Es kann helfen, auf schnelle Discs zu setzen. Wie RAM-Discs

2) Haben Sie eine In-Memory-Datenbank. Einfach vom Code und schnell starten. In den meisten Fällen verhält es sich jedoch genauso wie Ihre Produktionsdatenbank. Dies ist weniger wichtig, wenn Sie etwas verwenden, das den Unterschied zu verbergen versucht. Ich benutze oft eine In-Memory-Datenbank für die erste Build-Phase und die reale Sache in einer zweiten Phase.

Laden der Testdaten

1) Leute sagen mir, dass ich dbunit benutzen soll. Ich bin nicht davon überzeugt, dass es viel XML zu sein scheint und schwer zu pflegen ist, wenn sich Spalten oder Einschränkungen ändern.

2) Ich bevorzuge normalen Anwendungscode. (Java + Hibernate) in meinem Fall, aber der Code, der Sie Daten in die Datenbank in der Produktion schreibt, sollte in vielen Fällen geeignet sein, Testdaten für Ihren Test zu schreiben. Es hilft, eine kleine spezielle API zu haben, die die Details der Befriedigung aller Fremdschlüssel und Sachen versteckt: Ссылка

    
Jens Schauder 23.04.2012 21:15
quelle
0

Das kannst du nicht, wirklich. Sie benötigen eine statische Datengruppe, um zuverlässige Komponententests zu erstellen. Vielleicht funktioniert ein Datenbank-Snapshot für Sie.

Dynamische Daten können auf andere Weise nützlich sein, z. B. um Regressionstests durchzuführen ...

    
PinnyM 23.04.2012 20:55
quelle
0

Die meisten Tests konzentrieren sich auf die Logikpfade, die zum Beispiel beim Abrufen von Daten erforderlich sind. Nicht auf die Gültigkeit der Daten selbst. Die Gültigkeit der Daten ist nur dann sinnvoll, wenn Ihre Anwendung sie irgendwie berechnet oder aggregiert. In diesem Fall sollten Sie in der Lage sein, die Eingaben zu kontrollieren und sicherzustellen, dass die Ergebnisse korrekt sind.

Das heißt, manchmal möchten Sie die gleiche Datenbank verwenden, die Ihre App verwendet, um die Rückgabe zu überprüfen. Wenn Sie beispielsweise eine Funktion testen, die ein gefiltertes Dataset zurückgibt, kann der Komponententest dieselbe Abfrage ausführen und dann zeilenweise einen Vergleich beispielsweise für jeden primären Schlüssel des Datensatzes durchführen und sicherstellen, dass Ihre Funktion den Wert zurückgegeben hat gleiche Datenmenge, die Sie erwartet haben.

Ich weiß nicht, ob das Ihre spezifische Frage ist, aber es ist nichts falsch daran, die Datenbank zu schlagen, um Behauptungen in Komponententests auszuführen, im Gegenteil. Zumindest mache ich es die ganze Zeit und niemand hat versucht mich festnehmen zu lassen:)

    
kprobst 23.04.2012 20:56
quelle
0

Ich ignoriere die Tatsache, dass Sie über die DB sprechen. Ich denke, dass Sie nach Ihren Unit-Tests suchen, um alle Eventualitäten abzudecken, da dies zu sinkenden Renditen führen kann. Wenn ich Sie wäre, würde ich einen Standardpfad und dann ein paar Randfälle abdecken. Tatsache ist, dass Sie nicht alles pragmatisch testen können.

Hier ist eine weitere Lektüre

Ссылка
Wie tief sind Ihre Unit-Tests?
Ссылка
Ссылка

Wenn Sie Ihr spezifisches db-bezogenes Problem betrachten, müssen Sie, um diese Funktion zu testen, wahrscheinlich ein Naht , um die Daten vorzubelegen, damit Sie diese Fälle abdecken können.

    
Johnno Nolan 23.04.2012 21:01
quelle
0

Ich würde die Daten im Test selbst erstellen. So können Sie auch komplizierte Szenarien für die sich ständig ändernden Daten testen. Der entscheidende Punkt ist, dass Sie die Datenänderungen in Ihren Tests steuern können, indem Sie eine dedizierte Test-Datenbank verwenden,

Schritt 1: Fügen Sie die benötigten Daten in eine db ein, die nur vom Test verwendet wird Schritt 2: Die Datenbank befindet sich jetzt in einem stabilen, vorhersagbaren Zustand. Sie können also Ihre Abfragen ausführen und die Ausgabe testen

    
TGH 24.04.2012 05:01
quelle