writing unit tests with spock framework
Schreiben von Unit-Tests mit Spock Framework: Testvorrichtungen, Zusicherungen und Berichterstellung
In diesem Komplette Anleitung für Anfänger zu Spock , ein kurzer Einführung in Spock Framework und Groovy-Programmierung wurde in unserem vorherigen Tutorial gegeben.
In diesem Tutorial werden wir alle Details / Schritte durchgehen, die für den Einstieg erforderlich sind Unit Testing in Spock.
Der Einfachheit halber werden wir eine einfache Taschenrechneranwendung testen, die verschiedene Methoden wie Addition, Subtraktion, Multiplikation, Division usw. enthält, die alle ganzzahlige Parameter akzeptieren und eine ganzzahlige Ausgabe zurückgeben.
Was du lernen wirst:
- Unit Testing mit Spock Video Tutorial
- Einstieg
- Schlüsselwort 'def'
- Der Lebenszyklus einer Spock-Spezifikation
- Spock-Behauptungen
- Berichterstattung
- Fazit
- Literatur-Empfehlungen
Unit Testing mit Spock Video Tutorial
Einstieg
Ähnlich wie bei allen anderen Unit-Test-Frameworks kann auch Spock zum Schreiben von Szenarien / Testfällen für eine zu testende Anwendung verwendet werden. Wir werden versuchen, die verschiedenen Funktionen des Spock-Frameworks mit den vorhandenen / bekannten Frameworks wie z JUnit .
Schlüsselwort 'def'
Versuchen wir zunächst, das Schlüsselwort 'def' von Groovy kurz zu verstehen. Das Schlüsselwort def wird zum Definieren des Typs def verwendet und kann zum Deklarieren einer Funktion sowie eines Felds / einer Variablen verwendet werden.
'Def' wird im Allgemeinen verwendet, wenn wir den Feldtyp oder den Rückgabetyp einer Methode nicht einschränken möchten. Sehen wir uns einige Beispiele für das Schlüsselwort def in einer groovigen Klasse und all ihre gültigen Verwendungen an.
// def as variable types def inputNum = 100 def inputStr = 'hello world!!' def app = new CalculatorApp() // def as return type of function def 'test function'() { // function body here }
Der Lebenszyklus einer Spock-Spezifikation
Wenn die Spock-Spezifikation ausgeführt wird, sucht sie nach allen definierten Tests und führt sie einzeln aus. Es gibt jedoch nur wenige andere Funktionen, die von Spock bereitgestellt werden, um Tests weniger redundant und lesbarer zu machen.
Lassen Sie uns nachfolgend einige Funktionen diskutieren:
Definieren von Eingaben / Variablen als Teil von Spec
Erwägen Sie mehrere Tests, die alle dieselben Eingabewerte verwenden. Eine Möglichkeit wäre, die Eingabewerte in jedem Test einzeln zu initialisieren. Andernfalls können wir die Felder direkt auf Spezifikationsebene definieren und sicherstellen, dass die Felder vor jedem Test initialisiert werden und für den auszuführenden Test verfügbar sind.
Sehen wir uns ein Beispiel für unsere Taschenrechner-Anwendungsklasse an .
Wir werden die Eingabedaten auf Spezifikationsebene definieren, damit sie mit den Anfangswerten für alle in der Spezifikation vorhandenen Tests verfügbar sind.
class CalculatorAppSpec extends Specification { def input1 = 50 def input2 = 10 def result = 0 def app = new CalculatorApp() def 'addition with valid inputs return expected result'() { when: result = app.add(input1, input2) then: result == 60 } def 'multiplication with valid inputs return expected result'() { when: result = app.multiply(input1, input2) then: result == 500 } def 'division with valid inputs return expected result'() { when: result = app.divide(input1, input2) then: result == 5 } def 'subsctraction with valid inputs return expected result'() { when: result = app.substract(input1, input2) then: result == 40 } }
In diesem Codebeispiel sehen Sie, dass wir input1, input2, die zu testende Anwendung und das Ergebnis auf Spezifikationsebene definiert haben. Dies stellt sicher, dass jedes Mal, wenn ein Test aus den Spezifikationsdateien ausgeführt wird und die initialisierten Felder an diesen Test übergeben werden. Dadurch entfällt in der Tat die Notwendigkeit, jedes Mal Tests mit Eingabewerten einzurichten.
Prüfvorrichtungen
Ähnlich wie bei den meisten Unit-Test-Frameworks bietet Spock auch Setup- und Bereinigungsmethoden zum Ausführen spezieller Logik / Aufgaben bei bestimmten Lebenszyklusereignissen der Testausführung.
setupSpec & cleanupSpec
Diese Methoden werden für jede Spezifikationsausführung einmal aufgerufen und vor bzw. nach der Testausführung aufgerufen. Diese sind vergleichbar mit @ Vor dem Unterricht und @ Nach dem Unterricht Anmerkungen von JUnit.
Einrichtung & Bereinigung
Diese Methoden werden vor und nach der Ausführung jedes Tests in der Spezifikation aufgerufen.
Diese Hooks sind der richtige Ort für jede Logik / jeden Code, den Sie vor und nach der Testausführung ausführen möchten. Zum Beispiel , Bei der Bereinigung können Sie einen Code schreiben, um die Datenbankverbindung (falls vorhanden) zu schließen, die während des Tests verwendet wurde.
Diese können mit @ verglichen werden BeforeTest und @ AfterTest Anmerkungen in der JUnit.
Ein Beispiel für diese Geräte finden Sie in unserem Taschenrechner-Anwendungstest.
def setupSpec() { println('###in setup spec!') } def cleanupSpec() { println('###in cleanup spec!') } def setup() { println('>>>in test setup!') } def cleanup() { println('>>>in test cleanup!') }
Wenn der obige Testvorrichtungscode zu einer Spezifikation hinzugefügt wird, die 4 Tests enthält, lautet die Ausgabe wie folgt:
###in setup spec! >>>in test setup! >>>in test cleanup! >>>in test setup! >>>in test cleanup! >>>in test setup! >>>in test cleanup! >>>in test setup! >>>in test cleanup! ###in cleanup spec!
Spock-Behauptungen
Die Behauptungen in Spock werden Power Assert genannt (und sie wurden später von Groovy übernommen, nachdem sie von Spock eingeführt wurden). Die Spock-Assertions bieten viele diagnostische Ausnahmen für den Fall, dass Assertionsfehler auftreten.
Man kann leicht herausfinden, was schief gelaufen ist, indem man einfach die Fehlerdiagnose im Gegensatz zur ausführlichen betrachtet AssertionErrors in JUnit und anderen Frameworks.
Versuchen wir, dies anhand eines Beispiels zu verstehen und JUnit gegenüberzustellen
Wir werden mit einem einfachen Test arbeiten, der die Gleichheit der Zeichenfolgen überprüft und feststellt, welche Diagnosen im Falle eines Assertionsfehlers generiert werden.
Spock-Test
def 'check case-insensitive equality of 2 strings'() { given: 'two input strings' String str1 = 'hello' String str2 = 'HELLO world' when: 'strings are lowercased' str1 = str1.toLowerCase() str2 = str2.toLowerCase() then: 'equal strings should return success' str1 == str2 }
JUnit-Test
@Test public void compareStrings_withValidInput_shouldReturnSuccess() { // Arrange String str1 = 'hello'; String str2 = 'HELLO world'; // Act str1 = str1.toLowerCase(); str2 = str2.toLowerCase(); // Assert Assert.assertEquals(str1,str2); }
Spock-Ausgabe
Condition not satisfied: str1 == str2 | | | hello| hello world false 6 differences (45% similarity) hello(------) hello( world) Expected :hello world Actual :hello
JUnit-Ausgabe
org.junit.ComparisonFailure: Expected :hello Actual :hello world
Wie Sie oben schließen können, sind die von Spock bereitgestellten Diagnoseinformationen detaillierter und benutzerfreundlicher als die anderen Frameworks wie JUnit.
Tipps und Tricks zur Behauptung
Mehrere Elemente gleichzeitig bestätigen - Spock bietet verschiedene Abkürzungen für Zusicherungen. Eine davon ist die '*' - Notation, mit der die Elemente in der Liste bestätigt werden können.
Lassen Sie uns dies anhand eines Beispiels verstehen:
Stellen Sie sich eine CityInfo-Klasse mit cityName und Population als Feldern vor. Wir werden einen Spock-Test schreiben, um die Namen der Städte zu bestätigen, die in der angegebenen Liste enthalten sind.
public class CityInfo { public CityInfo(String cityName, int population) { this.cityName = cityName; this.population = population; } public String cityName; public int population; }
Sehen wir uns jetzt den Test an:
def 'Assert multiple elements of list' () { given: def cityList = new LinkedList() cityList.add(new CityInfo('Mumbai', 120)) cityList.add(new CityInfo('Delhi', 80)) cityList.add(new CityInfo('Chennai', 100)) expect: cityList*.cityName == ['Mumbai', 'Delhi', 'Chennai'] }
Wie in der obigen Abkürzung für die Zusicherung gezeigt, können Sie die gesamte Liste mit Hilfe des Schlüsselworts '*' validieren.
Mal sehen, wie ein Fehler ausgesehen hätte. Ich werde den Namen einer Stadt aus der obigen Behauptung entfernen.
Condition not satisfied: cityList*.cityName == ['Delhi', 'Chennai'] | | | | | false | [Mumbai, Delhi, Chennai] [app.CityInfo@31368b99, app.CityInfo@1725dc0f, app.CityInfo@3911c2a7]
Sie können sehen, dass die Diagnoseinformationen zu Assertionsfehlern umfangreich und leicht zu verstehen sind.
Verschlussparameter nutzen - every ().
Mal sehen, wie wir den Abschlussparameter namens every () nutzen können, um eine Zusicherung für jedes Element einer Liste oder Sammlung hinzuzufügen. Versuchen wir im selben Beispiel, eine Behauptung hinzuzufügen, die die Bevölkerung jeder Stadt überprüft, wenn die angegebene Eingabe> 50 ist.
def 'Assert multiple elements of list' () { given: def cityList = new LinkedList() cityList.add(new CityInfo('Mumbai', 120)) cityList.add(new CityInfo('Delhi', 80)) cityList.add(new CityInfo('Chennai', 100)) expect: cityList*.cityName == ['Mumbai', 'Delhi', 'Chennai'] and: cityList.population.every() { it > 50 } }
Geworfene Ausnahmen geltend machen
Es kann behauptet werden, dass Ausnahmen in den 'dann' -Block geworfen werden (was bedeutet, dass der Block auch benötigt wird). Das Ausnahmedetail kann diagnostiziert werden, indem die ausgelöste Ausnahme einem Feld zugewiesen und die erforderlichen Eigenschaften der ausgelösten Ausnahme bestätigt werden.
Verwenden wir dieselbe CityInfo-Klasse und definieren eine Methode, die eine Ausnahme auslöst, und schreiben einen Test dafür.
public class CityInfo { public CityInfo(String cityName, int population) { this.cityName = cityName; this.population = population; } public String cityName; public int population; public CityInfo() { } public int getCleanlinessScore() { throw new RuntimeException('method not implemented'); } }
Schauen wir uns jetzt den Test an:
def 'cleanliness score throws runtime exception with message - method not implemented'() { given: CityInfo app = new CityInfo(); when: app.cleanlinessScore() then: def e = thrown(RuntimeException) e.message == 'method not implemented' }
Berichterstattung
Um schöne und detaillierte HTML-basierte Berichte zu erstellen, stehen Bibliotheken zur Verfügung, die in die Build-Datei eingefügt werden können. Wenn die Tests während des Builds (oder durch direkte Ausführung) ausgeführt werden, wird in der Datei ein detaillierter HTML-basierter Bericht generiert Ausgabeordner.
Fügen Sie der Datei build.gradle (und ähnlich auch der Datei Maven pom.xml) die folgenden Bibliotheken hinzu, um die Testberichte zu generieren.
testCompile 'com.athaydes:spock-reports:1.6.1' testCompile 'org.slf4j:slf4j-api:1.7.13' testCompile 'org.slf4j:slf4j-simple:1.7.13'
Erstellen Sie nun das Projekt und führen Sie die Tests aus, indem Sie alle Tests im Ordner 'test' ausführen oder 'ausführen'. Gradle Clean Test ”.
Du kannst öffnen index.html Datei, um einen zusammengefassten Bericht für alle Spock-Spezifikationen zu erhalten, die zur Ausführung verfügbar waren.
Wenn Sie den detaillierten Bericht für eine bestimmte Spezifikation anzeigen möchten, klicken Sie auf die Spezifikation in der obigen Liste, um einen detaillierten Bericht über Fehler und Erfolge anzuzeigen.
Fragen und Antworten zum Datenbankdesign-Interview
Fazit
In diesem Tutorial haben wir die Grundlagen des Unit-Testens mit Spock Framework behandelt. Wir haben die verschiedenen Methoden und Abkürzungen zum Schreiben von Zusicherungen und die umfangreichen Diagnoseinformationen gesehen, die vom Spock-Framework für Durchsetzungsfehler generiert wurden.
Wir haben uns auch angesehen, wie wir für die Spock-Tests ziemlich hübsche HTML-basierte Berichte erstellen können, die dieselbe detaillierte Diagnose für die ausgeführten Tests enthalten.
In unserem nächsten Tutorial erfahren Sie ausführlich, wie Sie parametrisierte Tests mit Spock schreiben können.
PREV Tutorial | NÄCHSTES Tutorial
Literatur-Empfehlungen
- Datengesteuertes oder parametrisiertes Testen mit Spock Framework
- Spock Interview Fragen mit Antworten (am beliebtesten)
- Spock für Integration und Funktionstests mit Selen
- Spock Mocking and Stubbing (Beispiele mit Video-Tutorials)
- Spock Tutorial: Testen mit Spock und Groovy
- Mockito Tutorial: Mockito Framework zum Verspotten im Unit Testing
- Die Unterschiede zwischen Unit Testing, Integration Testing und Functional Testing
- Schlüssel zum erfolgreichen Testen von Einheiten - Wie testen Entwickler ihren eigenen Code?