7 reasons why bother learning spock

54
7 reasons why bother learning Spock (for Java developers) Riga, 6th September 2016

Upload: latcraft

Post on 14-Jan-2017

124 views

Category:

Software


3 download

TRANSCRIPT

Page 1: 7 reasons why bother learning Spock

7reasonswhybotherlearningSpock(forJavadevelopers)

Riga,6thSeptember2016

Page 2: 7 reasons why bother learning Spock

AboutmeAreasofexpertise

AutomaticTesting/TDD(withSpockofcourse:))

SoftwareCraftsmanship/CodeQuality

Concurrency/ParallelComputing/ReactiveSystems

DeploymentAutomation/ContinuousDelivery

FOSSprojectsauthorandcontributor,blogger,trainer

CTOofsmallsoftwarehouse-Codearte

targetedatclientswhocareaboutthequality

TrainerinBottegaITSolutions

Page 3: 7 reasons why bother learning Spock

WhybotherlearningSpock?

Page 4: 7 reasons why bother learning Spock

Reason1BDDspecificationbydefault

Page 5: 7 reasons why bother learning Spock

BDDspecificationbydefaultclassSimpleCalculatorSpecextendsSpecification{

def"shouldsumtwonumbers"(){given:Calculatorcalculator=newSimpleCalculator()when:intresult=calculator.sum(1,2)then:result==3}}

Page 6: 7 reasons why bother learning Spock

BDDspecificationbydefaultclassSimpleCalculatorSpecextendsSpecification{

def"shouldsumtwonumbers"(){given:Calculatorcalculator=newSimpleCalculator()when:intresult=calculator.sum(1,2)then:result==3}

[given]/when/then(orexpect)arerequiredtocompilecode

notjustcommentsincode

Page 7: 7 reasons why bother learning Spock

Reason2PowerAssertions

Page 8: 7 reasons why bother learning Spock

PowerAssertions-basiccasereusedJavaassertkeyword

assert(2+3)*4!=(2*4)+(3*4)

Page 9: 7 reasons why bother learning Spock

PowerAssertions-basiccasereusedJavaassertkeyword

assert(2+3)*4!=(2*4)+(3*4)

selfexplainingreasonoffailure

Assertionfailed:

assert(2+3)*4!=(2*4)+(3*4)||||||520false82012

Page 10: 7 reasons why bother learning Spock

PowerAssertions-morecomplexcasenotonlymathematicalexpressions

Stringword="Spock"intbegin=1intend=3assertword.substring(begin,end)==word[begin..end]

Page 11: 7 reasons why bother learning Spock

PowerAssertions-morecomplexcasenotonlymathematicalexpressions

Stringword="Spock"intbegin=1intend=3assertword.substring(begin,end)==word[begin..end]

alsoformethodreturntypesandarguments

Assertionfailed:

assertword.substring(begin,end)==word[begin..end]||||||||||po13|||13Spock||poc|Spockfalse

Page 12: 7 reasons why bother learning Spock

PowerAssertions-othercomplexcaseevenforcomplicatedstructuresandexpressions

assertann.name==bob.name&&ann.age==bob.age

Page 13: 7 reasons why bother learning Spock

PowerAssertions-othercomplexcaseevenforcomplicatedstructuresandexpressions

assertann.name==bob.name&&ann.age==bob.age

detailedevaluationofsubelements

Assertionfailed:

assertann.name==bob.name&&ann.age==bob.age|||||||Ann||Bobfalse||Person(name:Bob,age:7)|falsePerson(name:Ann,age:4)

Page 14: 7 reasons why bother learning Spock

PowerAssertions-othercomplexcaseevenforcomplicatedstructuresandexpressions

assertann.name==bob.name&&ann.age==bob.age

detailedevaluationofsubelements

Assertionfailed:

assertann.name==bob.name&&ann.age==bob.age|||||||Ann||Bobfalse||Person(name:Bob,age:7)|falsePerson(name:Ann,age:4)

secondpartignoredasmeaningless

Page 15: 7 reasons why bother learning Spock

PowerAssertionsself-explaining

optionalassertkeywordinthenandexpectcodeblock

unlessplacedinClosureorseparatemethod

backportedtoGroovy

Page 16: 7 reasons why bother learning Spock

Reason3Firstclasssupport

forparameterizedtests

Page 17: 7 reasons why bother learning Spock

Parameterizedtestsdef"shouldsumtwointegers"(){given:Calculatorcalculator=newSimpleCalculator()when:intresult=calculator.add(x,y)then:result==expectedResultwhere:x|y||expectedResult1|2||3-2|3||1-1|-2||-3}

Page 18: 7 reasons why bother learning Spock

Parameterizedtestsdef"shouldsumtwointegers"(){given:Calculatorcalculator=newSimpleCalculator()when:intresult=calculator.add(x,y)then:result==expectedResultwhere:x|y||expectedResult1|2||3-2|3||1-1|-2||-3}

build-insupportwithwherekeyword

doesnotstoponfailureforgiventestcase

syntacticsugarfortable-likedataformatting

Page 19: 7 reasons why bother learning Spock

Parameterizedtests-evenbetter@Unrolldef"shouldsumtwointegers(#x+#y=#expectedResult)"(){given:Calculatorcalculator=newSimpleCalculator()when:intresult=calculator.add(x,y)then:result==expectedResultwhere:x|y||expectedResult1|2||3-2|3||1-1|-2||-3}

separatetestforeveryinputparametersset-@UnrollvisiblealsoinreportsandIDEinputparameterspresentedintestname(with#)

datapipesanddataprovidersforadvancedusecases

Page 20: 7 reasons why bother learning Spock

Reason4Built-inmockingframework

Page 21: 7 reasons why bother learning Spock

SimpleStubbingclassDaoSpecextendsSpecification{

def"shouldstubmethodcall"(){given:Daodao=Stub()dao.getCount()>>1expect:dao.getCount()==1}}

interfaceDao{intgetCount()Itemsave(Itemitem)}

Page 22: 7 reasons why bother learning Spock

SimpleStubbing-customlogicclassDaoSpecextendsSpecification{

def"shouldthrowexceptionforspecificinputparameters"(){given:Dao<Item>dao=Stub()dao.save(_)>>{Itemitem->thrownewIllegalArgumentException(item.toString())}when:dao.save(newItem())then:thrown(IllegalArgumentException)}}

_foranyargumentvalue

argumentsavailableinsideClosure

Page 23: 7 reasons why bother learning Spock

MockinteractionsverificationclassDaoSpecextendsSpecification{

def"shouldstubandverify"(){given:ItembaseItem=newItem()and:Dao<Item>dao=Mock()when:dao.delete(baseItem)then:1*dao.delete(_)}}

1*-methodcalledonce

(_)-withanyvalueasthefirstparameter

Page 24: 7 reasons why bother learning Spock

StubbingandverifyingtogetherclassDaoSpecextendsSpecification{

def"shouldstubandverify"(){given:ItembaseItem=newItem()and:Dao<Item>dao=Mock()when:ItemreturnedItem=dao.save(baseItem)then:1*dao.save(_)>>{Itemitem->item}and:baseItem.is(returnedItem)}}

hastobedefinedinthesamestatementinthensection

Page 25: 7 reasons why bother learning Spock

StubbingandverifyingtogetherclassDaoSpecextendsSpecification{

def"shouldstubandverify"(){given:ItembaseItem=newItem()and:Dao<Item>dao=Mock()when:ItemreturnedItem=dao.save(baseItem)then:1*dao.save(_)>>{Itemitem->item}and:baseItem.is(returnedItem)}}

hastobedefinedinthesamestatementinthensectiondesignsuggestion:inmostcasesstubbingandinteractionverificationofthesamemockshouldn'tbeneeded

Page 26: 7 reasons why bother learning Spock

Reason5Exceptiontesting

Page 27: 7 reasons why bother learning Spock

Capturingthrownexceptiondef"shouldcaptureexception"(){when:throwNPE()then:NullPointerExceptione=thrown()e.message=="testNPE"}

Page 28: 7 reasons why bother learning Spock

Capturingthrownexceptiondef"shouldcaptureexception"(){when:throwNPE()then:NullPointerExceptione=thrown()e.message=="testNPE"}

thrownexceptioninterceptedandassignedtovariable

forfurtherasserting

testfailedifnotthrown

orhasunexpectedtype

Exceptionsutilityclasstoplaywithcausechain

Page 29: 7 reasons why bother learning Spock

Reason6Groovymagic

Page 30: 7 reasons why bother learning Spock

Groovy-whybother?smarter,shorten,morepowerfulJava

Closuretomakefunctionsfirst-classcitizen

Javacode(inmostcases)isalsovalidGroovycode

flatlearningcurve

seamlesslyintegrationwithJavacode

canuseJavalibraries

Page 31: 7 reasons why bother learning Spock

Groovy-listsandsetscompactsyntaxforlistandsetcreation

List<String>names=['Ann','Bob','Monica','Scholastica']

Set<Integer>luckyNumbers=[4,7,9,7]asSet//4,7,9

Page 32: 7 reasons why bother learning Spock

Groovy-listsandsetscompactsyntaxforlistandsetcreation

List<String>names=['Ann','Bob','Monica','Scholastica']

Set<Integer>luckyNumbers=[4,7,9,7]asSet//4,7,9

accessing

StringsecondName=names[1]//BobStringlastName=names[-1]//Scholastica

Page 33: 7 reasons why bother learning Spock

Groovy-listsandsetscompactsyntaxforlistandsetcreation

List<String>names=['Ann','Bob','Monica','Scholastica']

Set<Integer>luckyNumbers=[4,7,9,7]asSet//4,7,9

accessing

StringsecondName=names[1]//BobStringlastName=names[-1]//Scholastica

modification

names[1]='Alex'//Ann,Alex,Monica,Scholasticanames<<'John'//Ann,Alex,Monica,Scholastica,JohnSet<Integer>withoutSeven=luckyNumbers-7//4,9

Page 34: 7 reasons why bother learning Spock

Groovy-mapscompactsyntaxformapcreation

Map<String,Integer>childrenWithAge=[Ann:5,Bob:7,Monica:9,Scholastica:7]

Page 35: 7 reasons why bother learning Spock

Groovy-mapscompactsyntaxformapcreation

Map<String,Integer>childrenWithAge=[Ann:5,Bob:7,Monica:9,Scholastica:7]

accessing

childrenWithAge['Ann']//5

Page 36: 7 reasons why bother learning Spock

Groovy-mapscompactsyntaxformapcreation

Map<String,Integer>childrenWithAge=[Ann:5,Bob:7,Monica:9,Scholastica:7]

accessing

childrenWithAge['Ann']//5

modification

childrenWithAge['Bob']=8//Ann:5,Bob:8,Monica:9,Scholastica:7

Map<String,Integer>withAlice=childrenWithAge+[Alice:3]//Ann:5,Bob:8,Monica:9,Scholastica:7,Alice:3

Page 37: 7 reasons why bother learning Spock

FunctionalGroovy-Closuresoperationsoncollection

List<String>names=['Ann','Bob','Monica','Scholastica']

names.findAll{Stringname->name.length()>3}//Monica,Scholastica

Page 38: 7 reasons why bother learning Spock

FunctionalGroovy-Closuresoperationsoncollection

List<String>names=['Ann','Bob','Monica','Scholastica']

names.findAll{Stringname->name.length()>3}.collect{Stringname->//canbechainedname.toUpperCase()}//MONICA,SCHOLASTICA

Page 39: 7 reasons why bother learning Spock

FunctionalGroovy-Closuresoperationsoncollection

List<String>names=['Ann','Bob','Monica','Scholastica']

names.findAll{Stringname->name.length()>3}.collect{Stringname->//canbechainedname.toUpperCase()}//MONICA,SCHOLASTICA

ittorefersClosureexecutionargument-insimplecases

Set<Integer>luckyNumbers=[4,7,9,7]asSet

luckyNumbers.findAll{it%2==0}//4

Page 40: 7 reasons why bother learning Spock

FunctionalGroovy-Closuresinlinedfunctionalinterfaces

//productionJavamethodtocallvoidexecuteMultipleTimes(intnumber,RunnablecodeToExecute);

executeMultipleTimes(5,{println"Executed"})

//orsimplierexecuteMultipleTimes(5){println"Executed"}

Page 41: 7 reasons why bother learning Spock

(G)Stringsvariablereference

voidprintMagicNumber(intnumber){println"Todaymagicnumberis$number.Congrats!"}

Page 42: 7 reasons why bother learning Spock

(G)Stringsvariablereference

voidprintMagicNumber(intnumber){println"Todaymagicnumberis$number.Congrats!"}

methodexecution

println"Millisecondssincetheepoch:${System.currentTimeMillis()}."

Page 43: 7 reasons why bother learning Spock

(G)Stringsvariablereference

voidprintMagicNumber(intnumber){println"Todaymagicnumberis$number.Congrats!"}

methodexecution

println"Millisecondssincetheepoch:${System.currentTimeMillis()}."

multi-linestring

StringmailBody="""HelloUser,Welcometoournewsletter.Haveagoodday!"""

Page 44: 7 reasons why bother learning Spock

(G)Stringsvariablereference

voidprintMagicNumber(intnumber){println"Todaymagicnumberis$number.Congrats!"}

methodexecution

println"Millisecondssincetheepoch:${System.currentTimeMillis()}."

multi-linestring

StringmailBody="""HelloUser,Welcometoournewsletter.Haveagoodday!""".stripIndent()

Page 45: 7 reasons why bother learning Spock

Reason7Extensibility

Page 46: 7 reasons why bother learning Spock

Extensibilityverypowerfulextensionsmechanism

dozensofinternalfeaturesimplementedasextensions

providedout-of-box

@AutoCleanup,@IgnoreIf,@RestoreSystemProperties,...

manyextensionsasexternalprojects

abilitytoreuseJUnit's@Ruleand@ClassRule

Page 47: 7 reasons why bother learning Spock

Summary

Page 48: 7 reasons why bother learning Spock

WhySpock?consistandreadabletestcode

testsasspecificationbydefault

allGroovymagicavailabletohelp

chancetolearnnewlanguage

embeddedmockingframework

althoughMockitocanbeusedifpreferred(orneeded)

highlyextensible

compatiblewithtoolssupportingJUnit

Page 49: 7 reasons why bother learning Spock

What'snext?

Page 50: 7 reasons why bother learning Spock

What'snext?inmostcasesitisworthtogiveSpockatry

Page 51: 7 reasons why bother learning Spock

What'snext?inmostcasesitisworthtogiveSpockatry

andfallinlovewithitsreadabilityandsimplicity

Page 52: 7 reasons why bother learning Spock

What'snext?inmostcasesitisworthtogiveSpockatry

andfallinlovewithitsreadabilityandsimplicity

let'smakeasmallexperiment:)

writeallnewtestsinyourteam/projectentirelyinSpock

foraweek

decideifyoulikedit

tip:sampleSpockconfigurationforGradleandMavenavailableonmyblog

Page 53: 7 reasons why bother learning Spock

Questions?

MarcinZajączkowski

http://blog.solidsoft.info/@SolidSoftBlog

[email protected]

Page 54: 7 reasons why bother learning Spock

Thankyou!

MarcinZajączkowski

http://blog.solidsoft.info/@SolidSoftBlog

[email protected]