writing unit tests with spock framework
Testarea unității de scriere cu Spock Framework: Dispozitive de testare, afirmații și raportare
In acest Ghid complet pentru începători pe Spock , o scurtă Introducere în programarea Spock Framework și Groovy a fost dat în tutorialul nostru anterior.
În acest tutorial, vom parcurge toate detaliile / pașii necesari pentru a începe Testarea unității în Spock.
Din motive de simplitate, vom testa o aplicație simplă de calcul care are diferite metode cum ar fi adunarea, scăderea, înmulțirea, împărțirea etc., care acceptă parametri întregi și returnează o ieșire întreagă.
întrebări și răspunsuri la interviu pentru controlul calității pdf
Ce veți învăța:
- Testarea unității cu Spock Video Tutorial
- Noțiuni de bază
- Cuvânt cheie „def”
- Ciclul de viață al unei specificații Spock
- Afirmații Spock
- Raportarea
- Concluzie
- Lectură recomandată
Testarea unității cu Spock Video Tutorial
Noțiuni de bază
Similar oricărui alt cadru de testare a unității, și Spock poate fi folosit pentru a scrie scenarii / cazuri de testare pentru o aplicație testată. Vom încerca să comparăm și să contrastăm diferitele caracteristici ale cadrului Spock cu cadrele existente / cunoscute precum JUnit .
Cuvânt cheie „def”
Să încercăm mai întâi să înțelegem pe scurt cuvântul cheie „def” al Groovy. Cuvântul cheie def este utilizat pentru a defini tip-def și poate fi utilizat pentru a declara o funcție, precum și un câmp / variabilă.
„Def” este utilizat în general atunci când nu dorim să restricționăm tipul unui câmp sau să returnăm tipul unei metode. Să vedem câteva exemple de cuvinte cheie def într-o clasă groovy și toate utilizările sale valide.
// 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 }
Ciclul de viață al unei specificații Spock
Specificațiile Spock când sunt executate caută toate testele definite și le execută unul câte unul. Cu toate acestea, există puține alte funcționalități / caracteristici oferite de Spock pentru a face testele mai puțin redundante și mai lizibile.
Să discutăm mai jos câteva caracteristici:
Definirea intrărilor / variabilelor ca parte a spec
Luați în considerare efectuarea mai multor teste, toate folosind aceleași valori de intrare. O modalitate ar fi să inițializăm valorile de intrare în fiecare test individual, altfel putem defini direct câmpurile la nivelul specificațiilor și să ne asigurăm că înainte de fiecare test, câmpurile vor fi inițializate și disponibile testului care se execută.
Să vedem un exemplu pentru clasa noastră de aplicații de calculatoare .
Vom defini datele de intrare la nivelul specificațiilor, astfel încât acestea să fie disponibile împreună cu valorile inițiale pentru toate testele prezente în specificație.
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 } }
În acest eșantion de cod, puteți vedea că am definit input1, input2, aplicația testată și rezultatul la nivel de specificații. Ceea ce asigură acest lucru este că de fiecare dată când un test este rulat din fișierele de specificații și câmpurile inițializate sunt transmise testului respectiv. Acest lucru elimină într-adevăr necesitatea configurării testelor de fiecare dată cu valori de intrare.
Dispozitive de testare
Similar cu majoritatea cadrelor de testare unitară, Spock oferă, de asemenea, metode de configurare și curățare pentru executarea unor logici / sarcini speciale la evenimente specifice ciclului de viață ale executării testului.
setupSpec & cleanupSpec
Aceste metode sunt numite o dată pentru fiecare execuție Spec și sunt apelate înainte și după executarea testului. Acestea sunt comparabile cu @ Înainte de curs și @ După clasa adnotări de JUnit.
configurare și curățare
Aceste metode sunt apelate înainte și după executarea fiecărui test din spec.
Aceste cârlige sunt locul potrivit pentru orice logică / bucată de cod pe care doriți să o executați înainte și după executarea testului. De exemplu , În curățare, puteți scrie un cod pentru a închide conexiunea la baza de date (dacă există) care a fost utilizată în timpul testului.
Acestea pot fi comparate cu @ BeforeTest și @ AfterTest adnotări în JUnit.
Să vedem un exemplu al acestor dispozitive în testul aplicației noastre de calculatoare.
def setupSpec() { println('###in setup spec!') } def cleanupSpec() { println('###in cleanup spec!') } def setup() { println('>>>in test setup!') } def cleanup() { println('>>>in test cleanup!') }
Dacă codul dispozitivului de testare de mai sus este adăugat la o specificație care conține 4 teste, atunci ieșirea va fi după cum urmează:
care este cel mai bun curățător gratuit de computer
###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!
Afirmații Spock
Afirmațiile din Spock se numesc power assert (și a fost adoptată de groovy mai târziu după ce a fost introdusă de Spock). Afirmațiile Spock oferă o mulțime de excepții de diagnostic în cazul unor eșecuri ale afirmării.
Se poate afla cu ușurință ceea ce nu a funcționat, uitându-se pur și simplu la diagnosticul de eșec, spre deosebire de detaliu AssertionErrors în JUnit și alte cadre.
Să încercăm să înțelegem acest lucru cu un exemplu și să îl contrastăm cu JUnit
Vom lucra cu un test simplu care verifică egalitatea șirurilor și vom vedea ce diagnostice sunt generate în caz de eșec al afirmației.
Testul Spock
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 }
Testul JUnit
@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); }
Ieșire Spock
Condition not satisfied: str1 == str2 | | | hello| hello world false 6 differences (45% similarity) hello(------) hello( world) Expected :hello world Actual :hello
Ieșire JUnit
org.junit.ComparisonFailure: Expected :hello Actual :hello world
După cum puteți deduce de mai sus, informațiile de diagnostic furnizate de Spock au detalii mai bune și sunt mai ușor de utilizat în comparație cu celelalte cadre precum JUnit.
Sfaturi și trucuri pentru afirmare
Afirmarea mai multor elemente în același timp - Spock oferă diverse stenografii pentru afirmații și una dintre acestea este notația „*” care permite afirmarea elementelor din listă.
Să înțelegem acest lucru cu un exemplu:
Luați în considerare o clasă CityInfo care are câmpul CityName și populație. Vom scrie un test Spock pentru a afirma numele orașelor care sunt acolo în lista dată.
public class CityInfo { public CityInfo(String cityName, int population) { this.cityName = cityName; this.population = population; } public String cityName; public int population; }
Să vedem testul acum:
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') }
După cum se arată în stenograma de mai sus, puteți valida întreaga listă cu ajutorul cuvântului cheie „*”.
Să vedem și cum ar fi arătat un eșec. Voi elimina numele oricărui oraș din afirmația de mai sus.
Condition not satisfied: cityList*.cityName == ('Delhi', 'Chennai') | | | | | false | (Mumbai, Delhi, Chennai) (app.CityInfo@31368b99, app.CityInfo@1725dc0f, app.CityInfo@3911c2a7)
Puteți vedea că informațiile de diagnostic ale eșecului afirmației sunt bogate și ușor de înțeles.
Utilizarea parametrului de închidere - fiecare ().
Să vedem, cum putem utiliza parametrul de închidere numit every () pentru a adăuga o afirmație pentru fiecare element al unei liste sau colecții. În același exemplu, să încercăm să adăugăm o afirmație care validează populația fiecărui oraș dacă intrarea dată este> 50.
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 } }
Afirmarea excepțiilor aruncate
Excepțiile pot fi afirmate pentru a fi aruncate în blocul „atunci” (ceea ce înseamnă a când este necesar și blocul). Detaliul excepției poate fi diagnosticat prin atribuirea excepției aruncate unui câmp și afirmarea proprietăților necesare ale excepției aruncate.
Să folosim aceeași clasă CityInfo și să definim o metodă care aruncă o excepție și să scriem un test pentru aceasta.
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'); } }
Să vedem acum testul:
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' }
Raportarea
Pentru a genera rapoarte frumoase și detaliate bazate pe HTML, există biblioteci disponibile care pot fi adăugate în fișierul de compilare și acum ori de câte ori testele sunt executate în timpul compilării (sau prin executare directă), un raport detaliat bazat pe html va fi generat în dosar de iesire.
Pentru a obține rapoartele de testare generate, adăugați următoarele biblioteci în fișierul build.gradle (și în mod similar și pentru fișierul Maven pom.xml).
testCompile 'com.athaydes:spock-reports:1.6.1' testCompile 'org.slf4j:slf4j-api:1.7.13' testCompile 'org.slf4j:slf4j-simple:1.7.13'
Acum construiți proiectul și executați testele executând toate testele din folderul „test” sau executând „ gradle test curat ”.
Puteți deschide index.html fișier pentru a obține un raport rezumat pentru toate specificațiile Spock care erau disponibile pentru a fi executate.
cel mai bun curat pentru Windows 10
Dacă doriți să vedeți raportul detaliat pentru o anumită specificație, faceți clic pe specificația din lista de mai sus și puteți vedea un raport detaliat al eșecurilor, precum și al succeselor.
Concluzie
În acest tutorial, am acoperit elementele de bază ale testării unitare cu Spock Framework. Am văzut diferitele moduri și prescurtări pentru scrierea afirmațiilor și tipul de informații de diagnosticare bogate generate de cadrul Spock pentru eșecurile afirmației.
De asemenea, ne-am uitat la modul în care am putea genera rapoarte silențioase bazate pe HTML pentru testele Spock, care includ aceleași diagnostice detaliate pentru testele executate.
Următorul nostru tutorial vă va informa despre scrierea detaliată a testelor parametrizate cu Spock !!
Lectură recomandată
- Testare bazată pe date sau parametrizată cu Spock Framework
- Întrebări de interviu cu răspunsuri Spock (Cele mai populare)
- Spock pentru integrare și testare funcțională cu seleniu
- Spock batjocură și stubbing (exemple cu tutoriale video)
- Tutorial Spock: Testare cu Spock și Groovy
- Tutorial Mockito: Mockito Framework pentru batjocură în testarea unității
- Diferențele dintre testarea unitară, testarea integrării și testarea funcțională
- Cheia testării unitare de succes - Cum își dezvoltă propriul cod propriul dezvoltator?