Geh Fakedb Datenbankemulation in Tests

Neulich habe ich Tests für ein Modul geschrieben, das mit einer Datenbank interagiert. Ich wollte das Testmodul nicht mit dieser Datenbank verknüpfen - dies stellt zusätzliche Anforderungen an die Umgebung, in der die Tests durchgeführt werden. Ich wollte nicht gleich Instanzen des Typs sql.Rows mit den erforderlichen Platten erstellen - für mich ist dieser Typ eine "Black Box" und ich möchte, dass dies auch so bleibt. Suche zum Thema fand auch nichts interessantes.


Ich wollte meine Entdeckung mit der Community teilen: In Go's Hauptdistribution gibt es ein fast fertiges Tool für solche Bedürfnisse: FakeDb.


Was kann dieses Tool?


Im Wesentlichen handelt es sich hierbei um die einfachste Datenbank, die jedoch als DB-Objekt voll funktionsfähig ist und in der Lage ist, Tabellen zu erstellen, aufzufüllen und einfache Beispiele daraus zu erstellen. Alle erstellten Tabellen sind temporär und existieren, solange die FakeDb-Instanz existiert. Außerdem sind eine Verzögerungsemulation beim Aufrufen eines Befehls und eine Emulationsausnahme verfügbar.


FakeDb-Befehle


Befehle bestehen aus Phrasen, die durch einen vertikalen Strich - | getrennt sind. Eine Phrase ist entweder ein Schlüsselwort oder ein Ausdruck der Form "Schlüssel = Wert". Wobei Schlüssel der Name der Spalte ist.


Wischen
Der Befehl löscht die Tabellen und gibt ein leeres Ergebnis zurück. Außerdem wird überprüft, ob kein Deadlock vorliegt.
Aufrufbeispiel:
WIPE


ERSTELLEN
Der Befehl erstellt eine Tabelle mit den angegebenen Spalten des angegebenen Typs.


Anruf format:


CREATE|_|1=,...,N=


Unterstützte Typen:


  • Dummkopf
  • nullbool - Boolescher Wert oder null
  • int32
  • Zeichenfolge
  • nullstring - string oder NULL
  • int64
  • nullint64 - int64 oder NULL
  • float64
  • nullfloat64 - float64 oder NULL
  • datetime
  • any - leere Schnittstelle, d. h. jeder Typ

Aufrufbeispiel:


CREATE|people|name=string,age=int32,photo=any,dead=bool,bdate=datetime


EINFÜGEN
Der Befehl fügt der erstellten Tabelle Zeilen hinzu.


Anruf format:
INSERT|_|1=,...,N
Im Folgenden kann der Wert auf drei Arten eingestellt werden:


  1. Geben Sie explizit einen Wert an, z. B. 123 .
  2. Geben Sie "?" An und übergeben Sie den Wert als Parameter.
  3. Geben Sie "? Parametername" an und übergeben Sie den Wert an den benannten Parameter.

Aufrufbeispiel:


INSERT|people|name=Alice,age=?,photo=?photo


SELECT
Mit dem Befehl können Sie entweder alle Zeilen der Tabelle oder eine Auswahl treffen.
Anruf format:


 SELECT|_|1,...,N| SELECT|_|1,...,N|1=?,...,M 

Aufrufbeispiel:


 SELECT|categories|category_id,category_parent_id,category_name| SELECT|categories|category_id,category_parent_id,category_name|category_parent_id=?parent 

Das Ergebnis ist eine vollständige Instanz von sql.Rows.


Warten
Simuliert eine Verzögerung bei der Ausführung eines Befehls. Muss vor einem der obigen Befehle hinzugefügt werden.
Anruf format:
WAIT||


Die Verzögerung wird als Größe und ein Postfix angegeben, das eine Maßeinheit angibt: s - Sekunden, n - Nanosekunden, u - Mikrosekunden, h - Stunden usw. (die Funktion time.ParseDuration () wird verwendet).


Aufrufbeispiel:
WAIT|1s|SELECT|categories|category_id,category_parent_id,category_name|


Panik
Löst beim Aufrufen eines Befehls eine Ausnahme aus.
Anruf format:
PANIC|_|


Der Wert von MethodName wird in das Feld stmt.panic (Typ fakeStmt).


Aufrufbeispiel:
PANIC|blablabla|SELECT|categories|category_id,category_parent_id,category_name|


Verwenden Sie


FakeDb wurde erstellt, um das "sql" -Paket der Hauptlieferung als Testskript zu testen . Ich habe es nicht in einem separaten Paket gefunden. Deshalb habe ich es selbst in einem Paket ausgewählt und hier abgelegt : gihub .


Kleinere Änderungen waren erforderlich, um das Paket hervorzuheben.


Anwendungsbeispiel


 package packname import ( "fmt" "testing" "io/ioutil" "database/sql" "github.com/a1div0/fakedb" ) func TestFoo(t *testing.T) { fc := &fakedb.FakeConnector{ } db := sql.OpenDB(fc) if db.Driver() != fakedb.Fdriver { t.Error("OpenDB should return the driver of the Connector") return } if _, err := db.Exec("WIPE"); err != nil { t.Error("exec wipe: %v", err) } defer db.Close() db.Exec("CREATE|users|user_email=string,user_id=int64") db.Exec("INSERT|users|user_email=?,user_id=?", "test@email.com", 345) rows, err := db.Query( "SELECT|users|user_id|user_email=?email", sql.Named("email", user_email), ) if err != nil { t.Error(err) } result, err := Foo(rows) //   if err != nil { t.Error(err) } if result != 123 { t.Error(" ,   Foo()   ;)") } } 

Vielen Dank für Ihre Aufmerksamkeit.


PS: Bitte schreiben Sie in die Kommentare - verwenden Sie bei den Tests die Datenbankemulation? Wenn ja, welches Paket?

Source: https://habr.com/ru/post/de485280/


All Articles