writing unit tests with spock framework
Skrivenhetstester med Spock Framework: Testarmaturer, påståenden och rapportering
I denna Komplett nybörjarguide på Spock , en kort Introduktion om Spock Framework och Groovy programmering gavs i vår tidigare handledning.
I den här handledningen går vi igenom alla detaljer / steg som krävs för att komma igång Enhetstestning i Spock.
För enkelhetens skull kommer vi att testa en enkel kalkylatorapplikation som har olika metoder som addition, subtraktion, multiplikation, division etc., som alla accepterar heltalsparametrar och returnerar en heltalsoutput.
Vad du kommer att lära dig:
- Enhetstestning med Spock Video Tutorial
- Komma igång
- 'Def' nyckelord
- Livscykeln för en Spock-specifikation
- Spock påståenden
- Rapportering
- Slutsats
- Rekommenderad läsning
Enhetstestning med Spock Video Tutorial
Komma igång
I likhet med alla andra testramar för enheter kan Spock också användas för att skriva scenarier / testfall för en applikation som testas. Vi försöker jämföra och kontrastera de olika funktionerna i Spock-ramverket med de befintliga / kända ramarna som JUnit .
'Def' nyckelord
Låt oss först försöka förstå Groovys 'def' nyckelord i korthet. Def-nyckelordet används för att definiera typ-def och kan användas för att deklarera en funktion såväl som ett fält / variabel.
'Def' används vanligtvis när vi inte vill begränsa typen av fält eller returtyp för en metod. Låt oss se några exempel på def-sökord i en groovy-klass och alla dess giltiga användningsområden.
// 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 }
Livscykeln för en Spock-specifikation
Spock-specifikation när den körs letar efter alla definierade tester och utför dem en efter en. Det finns dock få andra funktioner / funktioner som tillhandahålls av Spock för att göra tester mindre överflödiga och mer läsbara.
vad är det bästa gratisverktyget för borttagning av skadlig programvara
Låt oss diskutera några funktioner nedan:
Definiera ingångar / variabler som en del av Spec
Överväg att ha flera tester som alla använder samma ingångsvärden. Ett sätt skulle vara att initiera ingångsvärdena i varje test individuellt, annars kan vi direkt definiera fälten på specifik nivå och se till att fälten initialiseras och är tillgängliga för testet som körs före varje test.
Låt oss se ett exempel på vår applikationsklass för miniräknare .
Vi kommer att definiera ingångsdata på specifikationsnivå så att de kommer att finnas tillgängliga med initialvärdena för alla tester som finns i specifikationen.
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 } }
I det här kodprovet kan du se att vi har definierat input1, input2, applikationen som testas och resultat på specifik nivå. Vad detta säkerställer är att varje gång ett test körs från spec-filerna och de initialiserade fälten skickas till det testet. Detta eliminerar verkligen behovet av att ställa in test varje gång med inmatningsvärden.
Testa fixturer
I likhet med de flesta ramverk för enhetstestning tillhandahåller Spock också installations- och saneringsmetoder för att utföra speciell logik / uppgifter vid specifika livscykelhändelser för testkörning.
setupSpec & cleanupSpec
Dessa metoder anropas en gång för varje Spec-utförande och anropas före respektive efter utförandet av testet. Dessa är jämförbara med @ Innan lektionen och @ Efter lektionen anteckningar av JUnit.
installation och sanering
Dessa metoder kallas före och efter genomförandet av varje test i specifikationen.
Dessa krokar är rätt plats för logik / kod som du vill köra före och efter testkörning. Till exempel , Vid sanering kan du skriva en kod för att stänga databasanslutningen (om någon) som användes under testet.
Dessa kan jämföras med @ Före test och @ AfterTest anteckningar i JUnit.
Låt oss se ett exempel på dessa fixturer i vårt kalkylatorapplikationstest.
def setupSpec() { println('###in setup spec!') } def cleanupSpec() { println('###in cleanup spec!') } def setup() { println('>>>in test setup!') } def cleanup() { println('>>>in test cleanup!') }
Om ovanstående testfixturkod läggs till i en specifikation som innehåller 4 tester, blir resultatet som nedan:
hur man returnerar arrayer i java
###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 påståenden
Påståendena i Spock kallas power assert (och det antogs av groovy senare efter att ha introducerats av Spock). Spock-påståendena ger många diagnostiska undantag i händelse av påståendefel.
Man kan enkelt ta reda på vad som gick fel genom att helt enkelt titta på feldiagnostiken i motsats till den ordliga Påståendefel i JUnit och andra ramar.
Låt oss försöka förstå detta med ett exempel och kontrastera det med JUnit
Vi kommer att arbeta med ett enkelt test som kontrollerar om strängjämlikhet är och ser vilken diagnostik som genereras i händelse av ett påståendefel.
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-utgång
Condition not satisfied: str1 == str2 | | | hello| hello world false 6 differences (45% similarity) hello(------) hello( world) Expected :hello world Actual :hello
JUnit-utgång
org.junit.ComparisonFailure: Expected :hello Actual :hello world
Som du kan dra slutsatsen från ovan har den diagnostiska informationen från Spock bättre detaljer och är mer användarvänlig jämfört med andra ramverk som JUnit.
Tips och tricks för påståenden
Att hävda flera element samtidigt - Spock ger olika förkortningar för påståenden och en sådan är '*' -notering som gör det möjligt att hävda elementen i listan.
Låt oss förstå detta med ett exempel:
Tänk på en CityInfo-klass med cityName och population som fälten. Vi kommer att skriva ett Spock-test för att hävda namnen på städer som finns där i listan.
public class CityInfo { public CityInfo(String cityName, int population) { this.cityName = cityName; this.population = population; } public String cityName; public int population; }
Låt oss se testet nu:
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') }
Som visas i påståendet stenografi ovan kan du validera hela listan med hjälp av '*' nyckelordet.
Låt oss också se hur ett misslyckande skulle ha sett ut. Jag tar bort namnet på vilken stad som helst från påståendet ovan.
Condition not satisfied: cityList*.cityName == ('Delhi', 'Chennai') | | | | | false | (Mumbai, Delhi, Chennai) (app.CityInfo@31368b99, app.CityInfo@1725dc0f, app.CityInfo@3911c2a7)
Du kan se att den diagnostiska informationen om påståendefel är rik och lätt att förstå.
Utnyttja stängningsparameter - varje ().
Låt oss se hur vi kan utnyttja stängningsparametern som heter every () för att lägga till ett påstående för varje element i en lista eller samling. I samma exempel, låt oss försöka lägga till ett påstående som validerar befolkningen i varje stad om den angivna inmatningen är> 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 } }
Hävdar kastade undantag
Undantag kan hävdas kastas i ”då” -blocket (vilket betyder a när blocket också krävs). Undantagsdetaljer kan diagnostiseras genom att tilldela det kastade undantaget till ett fält och hävda de nödvändiga egenskaperna för det undantagna kastade.
Låt oss använda samma CityInfo-klass och definiera en metod som ger ett undantag och skriva ett test för det.
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'); } }
Låt oss titta på testet nu:
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' }
Rapportering
För att skapa vackra och detaljerade HTML-baserade rapporter finns det bibliotek tillgängliga som kan läggas till i byggfilen och nu när testerna körs under byggnaden (eller genom direkt körning) genereras en detaljerad html-baserad rapport i utmatningsmapp.
För att få testrapporterna genererade, lägg till följande bibliotek i filen build.gradle (och på samma sätt för Maven pom.xml-filen).
testCompile 'com.athaydes:spock-reports:1.6.1' testCompile 'org.slf4j:slf4j-api:1.7.13' testCompile 'org.slf4j:slf4j-simple:1.7.13'
Bygg nu projektet och kör testerna genom att köra alla tester i 'test' -mappen eller genom att köra ' gradle clean test ”.
Du kan öppna index.html fil för att få en sammanfattad rapport för alla Spock-specifikationer som var tillgängliga att köras.
hur man kör en jar-fil med java
Om du vill se den detaljerade rapporten för en specifik specifik, klicka sedan på specifikationen från listan ovan så kan du se en detaljerad rapport om misslyckanden såväl som framgångar.
Slutsats
I denna handledning behandlade vi grunderna för enhetstestning med Spock Framework. Vi såg de olika sätten och förkortningarna för att skriva påståenden och vilken typ av rik diagnostikinformation som genereras av Spock-ramverket för påståendefel.
Vi tittade också på hur vi kunde skapa tysta vackra HTML-baserade rapporter för Spock-testerna som innehåller samma detaljerade diagnostik för de utförda testerna.
Vår kommande handledning kommer att informera dig om att skriva parametrerade tester med Spock i detalj !!
PREV-handledning | NÄSTA självstudie
Rekommenderad läsning
- Datadriven eller parametrerad testning med Spock Framework
- Spock intervjufrågor med svar (mest populära)
- Spock för integration och funktionstestning med selen
- Spock Mocking and Stubbing (Exempel med videotutorials)
- Spock-handledning: Testning med Spock och Groovy
- Mockito Tutorial: Mockito Framework for Mocking in Unit Testing
- Skillnaderna mellan enhetstestning, integrationstestning och funktionstestning
- Nyckeln till framgångsrika enhetstester - Hur utvecklare testar sin egen kod?