SlideShare a Scribd company logo
1 of 50
Dmitry Voloshko
Smarter Testing
With Spock
What we’ll talk about
Spock?!
State Based Testing
Data Driven Testing
Interaction Based Testing
Spock Extensions
More Cool Stuff
Spock?!
Spock is...
A developer testing framework...
for Groovy and Java applications...
based on Groovy...
fully compatible with JUnit...
but going beyond!
Spock Can...
Reduce the lines of test code
Make tests more readable
Turn tests into specifications
Be extended in powerful ways
Bring back the fun to testing!
Getting Started
Homepage
http://spockframework.org
Source Code
https://github.com/spockframework/spock
Spock Web Console
http://meet.spockframework.org
Spock Example Project
http://downloads.spockframework.org
https://github.com/spockframework/spock/tree/groovy-1.8/spock-
example
Who’s Using Spock?
Gradle GPars
Grails Geb
Grails Plugin Collective
Apache Tapestry
Griffon Spock
Spring?
Who’s Using Spock?
Betfair be2
bemoko BSkyB CTI Digital
Donewtech Solutions
eHarmony
Energized Work Gennemtænkt IT
IntelliGrape Software Netflix
Smarter Ecommerce STERMEDIA Sp. z o.o.
Software Projects Spot Diving
SystemsForge TouK
State Based Testing
State Based Testing
Classical Unit Testing
Arrange
Act
Assert
Given-When-Then
The Code For Testing
Account.java
public class Account {
private BigDecimal balance = new BigDecimal(0);
public Account(BigDecimal initial) {
balance = initial;
}
public BigDecimal getBalance() {
return balance;
}
public void withdraw(BigDecimal amount) {
if (amount.compareTo(BigDecimal.ZERO) < 0) {
throw new NegativeAmountWithdrawnException(amount);
}
balance = balance.subtract(amount);
}
}
The Code For Testing
NegativeAmountWithdrawnException.java
public class NegativeAmountWithdrawnException extends RuntimeException {
private final BigDecimal amount;
public NegativeAmountWithdrawnException(BigDecimal amount) {
super("cannot withdraw" + amount);
this.amount = amount;
}
public BigDecimal getAmount() {
return amount;
}
}
Show me the code
public class AccountTest {
@Test
public void withdrawSomeAmount() {
// given
Account account = new Account(BigDecimal.valueOf(5));
// when
account.withdraw(BigDecimal.valueOf(2));
// then
assertEquals(BigDecimal.valueOf(3), account.getBalance());
}
}
Show me the code
class AccountSpec extends Specification {
def "withdraw some amount"() {
given:
Account account = new Account(BigDecimal.valueOf(5));
when:
account.withdraw(BigDecimal.valueOf(2));
then:
account.getBalance() == BigDecimal.valueOf(3);
}
}
Show me the code
class AccountSpec2 extends Specification {
def "withdraw some amount"() {
given:
def account = new Account(5.0)
when:
account.withdraw(2.0)
then:
account.balance == 3.0
}
}
Show me the code
class AccountSpec3 extends Specification {
def "withdraw some amount"() {
given: "an account with a balance of five euros"
def account = new Account(5.0)
when: "two euros are withdrawn"
account.withdraw(2.0)
then: "three euros remain in the account"
account.balance == 3.0
}
}
Show me the code
class AccountSpec4 extends Specification {
def "can't withdraw a negative amount"() {
given:
def account = new Account(5.0)
when:
account.withdraw(-1.0)
then:
NegativeAmountWithdrawnException e = thrown()
e.amount == -1.0
}
def "withdrawing some amount decreases the balance by exactly that amount"() {
def account = new Account(5.0)
when:
account.withdraw(2.0)
then:
account.balance == old(account.balance) - 2.0
}
}
Show me the code
class SharedField extends Specification {
@Shared File file
def "a file based test"() {
when:
file = new File("foo.txt")
file.createNewFile()
then:
file.exists()
}
def "by now the object is not null"() {
expect:
file.exists()
cleanup:
file.delete()
}
}
Show me the code
class SetupSpecSpec extends Specification {
File file
def setup() {
file = new File("foo2.txt")
}
def "a file based test"() {
when:
file.createNewFile()
then:
file.exists()
}
def "by now the object is not null"() {
expect: file.exists()
cleanup: file.delete()
}
}
Show me the code
class Conditions extends Specification {
def "when-then style"() {
when:
def x = Math.max(5, 9)
then:
x == 9
}
def "expect style"() {
expect:
Math.max(5, 9) == 9
}
def "more complex conditions"() {
expect:
germanCarBrands.any { it.size() >= 3 }
}
private getGermanCarBrands() { ["audi", "bmw", "porsche"] }
}
Recap: State Based Testing
Blocks
setup: cleanup: expect: given: when: then:
where: and:
Fixture Methods
setup() cleanup() setupSpec() cleanupSpec()
Instance and @Shared fields
old() and thrown()
Data Driven Testing
Data Driven Testing
Test the same behavior...
with varying data!
Show me the code
class AccountSpecDataDriven extends Specification {
@Unroll
def "withdraw some amount"() {
given:
def account = new Account(balance)
when:
account.withdraw(withdrawn)
then:
account.balance == remaining
where:
balance | withdrawn | |remaining
5.0 | 2.0 | | 3.0
4.0 | 0.0 | | 4.0
4.0 | 4.0 | | 0.0
}
}
Show me the code
class AccountSpecDataDriven extends Specification {
@Unroll
def "withdrawing #withdrawn from account with balance #balance"() {
given:
def account = new Account(balance)
when:
account.withdraw(withdrawn)
then:
account.balance == old(account.balance) – withdrawn
where:
balance | withdrawn
5.0 | 2.0
4.0 | 0.0
4.0 | 4.0
}
}
Show me the code
class AccountSpecDatabaseDriven extends Specification {
@Shared sql = Sql.newInstance("jdbc:h2:mem:", "org.h2.Driver")
def setupSpec() {
sql.execute("create table accountdata (id int primary key, balance decimal, withdrawn decimal, remaining decimal)")
sql.execute("insert into accountdata values (1, 5.0, 2.0, 3.0), (2, 4.0, 0.0, 4.0), (3, 4.0, 4.0, 0.0)")
}
@Unroll def "withdrawing #withdrawn from account with balance #balance leaves #remaining"() {
given:
def account = new Account(balance)
when:
account.withdraw(withdrawn)
then:
account.balance == remaining
where:
[balance, withdrawn, remaining] << sql.rows("select balance, withdrawn, remaining from accountdata")
}
}
Recap: Data Driven Testing
where: block
Data tables
External data sources
@Unroll
Interaction Based Testing
Interaction Based Testing
Design and test how your objects
communicate
Mocking frameworks to the rescue
Spock comes with its own mocking
framework
The Code For Testing
PublisherSubscriber.groovy
interface Subscriber {
void receive(String message)
}
class Publisher {
List<Subscriber> subscribers = []
void publish(String message) {
for (subscriber in subscribers) {
try {
subscriber.receive(message)
} catch (ignored) {}
}
}
}
The Code For Testing
PublisherSubscriber.groovy
interface Subscriber2 {
void receive(String message)
boolean isActive()
}
class Publisher2 {
List<Subscriber2> subscribers = []
void publish(String message) {
for (subscriber in subscribers) {
try {
if (subscriber.active) {
subscriber.receive(message)
}
} catch (ignored) {}
}
}
}
Show me the code
class PublisherSubscriberSpec extends Specification {
def pub = new Publisher()
def sub1 = Mock(Subscriber)
def sub2 = Mock(Subscriber)
def setup() {
pub.subscribers << sub2 << sub1
}
def "delivers messages to all subscribers"() {
when:
pub.publish("msg")
then:
1 * sub1.receive("msg")
1 * sub2.receive("msg")
}
}
Show me the code
class PublisherSubscriberSpec2 extends Specification {
def pub = new Publisher()
def sub1 = Mock(Subscriber)
def setup() {
pub.subscribers << sub1
}
def "delivers messages in the order they are published"() {
when:
pub.publish("msg1")
pub.publish("msg2")
then:
1 * sub1.receive("msg1")
then:
1 * sub1.receive("msg2")
}
}
Show me the code
class PublisherSubscriber2Spec extends Specification {
def pub = new Publisher2()
def sub1 = Mock(Subscriber2)
def sub2 = Mock(Subscriber2)
def setup() {
pub.subscribers << sub1 << sub2
}
def "delivers messages to all active subscribers"() {
sub1.active >> true
sub2.active >> false
when:
pub.publish("msg")
then:
1 * sub1.receive("msg")
0 * sub2.receive(_)
}
}
Recap: Interaction Based Testing
Creating
def sub = Mock(Subscriber)
Subscriber sub = Mock()
Mocking
1 * sub.receive("msg")
(1..3) * sub.receive(_)
(1.._) * sub.receive(_ as String)
1 * sub.receive(!null)
1 * sub.receive({it.contains("m")})
1 * _./rec.*/("msg")
Recap: Interaction Based Testing
Stubbing
// now returns status code
String receive(String msg) { ... }
sub.receive(_) >> "ok"
sub.receive(_) >>> ["ok", "ok", "fail"]
sub.receive(_) >>> { msg -> msg.size() > 3 ? "ok" : "fail" }
Mocking and Stubbing
3 * sub.receive(_) >>> ["ok", "ok", "fail"]
Impressing your friends
(_.._) * _._(*_) >> _
Spock Extensions
Spock Extensions
Listeners
Interceptors
Annotation-driven extensions
Global extensions
Built-in Extensions
@Ignore
@IgnoreRest
@FailsWith
@Timeout
@AutoCleanup
@Stepwise
@RevertMetaClass
@Rule
Show me the code
class JUnitRules extends Specification {
@Rule TemporaryFolder tempFolder
@Shared File file
def "a file based test"() {
when:
file = tempFolder.newFile("foo.txt")
then:
file.exists()
}
def "by now the file has been deleted"() {
expect:
!file.exists()
}
}
Show me the code
@Stepwise
class StepwiseSpec extends Specification {
def "step 1"() {
expect: true
}
def "step 2"() {
expect: true
}
def "step 3"() {
expect: true
}
}
External Extensions
spock-grails
spock-spring
spock-guice
spock-tapestry
spock-unitils
spock-griffon
spock-arquillian
spock-extensions http://github.com/robfletcher/spock-extensions
Grails Extensions
http://grails.org/plugin/spock
https://github.com/spockframework/spock-grails
grails install plugin spock 0.6
grails test-app
grails test-app unit:TestSpec
Grails Extensions
@TestFor(MouthService)
@Mock([Patient, PatientMouth, PatientTooth])
class MouthServiceSpec extends Specification {
def "Get patient tooth by index"() {
setup: "Create domain mocks"
def patient = new Patient(dateOfBirth: new Date('05/03/1984')).save(false)
def patientTooth = new PatientTooth(index: 10, toothCode: "10").save(false)
def patientMouth = new PatientMouth(patient: patient, patientTeeth: [patientTooth]).save(false)
when:
patientTooth = service.getPatientToothByIndex(patientMouth, index)
then:
patientTooth.toothCode == tooth
patientMouth.patientTeeth.contains(patientTooth)
where:
index | tooth
10 | "10"
20 | null
}
}
Spring Extension
class InjectionExamples extends Specification {
@Autowired
Service1 byType
@Resource
Service1 byName
@Autowired
ApplicationContext context
}
Other Cool Stuff
Configuring Spock
~/.spock/SpockConfig.groovy, or on class path, or with -Dspock.configuration
runner {
filterStackTrace false
include Fast
exclude Slow
optimizeRunOrder true
}
@Fast
class MyFastSpec extends Specification {
def "I’m fast as hell!"() { expect: true }
@Slow
def “Sorry, can’t keep up..."() {expect: false }
}
Tooling
Eclipse, IDEA
Ant, Maven, Gradle
Jenkins, Bamboo, TeamCity
Spock runs everywhere JUnit and Groovy run!
Spock Under The Hood
You write...
a = 1; b = 2; c = 4
expect: sum(a, b) == c
Spock generates...
def rec = new ValueRecorder()
verifier.expect(
rec.record(rec.record(sum(rec.record(a),
rec.record(b)) == rec.record(c)))
You see...
sum (a, b) == c
| | | | |
3 1 2 | 4
false
Q&A
Homepage
http://spockframework.org
Source Code
https://github.com/spockframework/spock
Spock Web Console
http://meet.spockframework.org
Spock Example Project
http://downloads.spockframework.org
https://github.com/spockframework/spock/tree/groovy-1.8/spock-example

More Related Content

What's hot

Grails/Groovyによる開発事例紹介
Grails/Groovyによる開発事例紹介Grails/Groovyによる開発事例紹介
Grails/Groovyによる開発事例紹介Kiyotaka Oku
 
Advanced Java Practical File
Advanced Java Practical FileAdvanced Java Practical File
Advanced Java Practical FileSoumya Behera
 
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...julien.ponge
 
Core java pract_sem iii
Core java pract_sem iiiCore java pract_sem iii
Core java pract_sem iiiNiraj Bharambe
 
Software Testing - Invited Lecture at UNSW Sydney
Software Testing - Invited Lecture at UNSW SydneySoftware Testing - Invited Lecture at UNSW Sydney
Software Testing - Invited Lecture at UNSW Sydneyjulien.ponge
 
Introduction to web programming for java and c# programmers by @drpicox
Introduction to web programming for java and c# programmers by @drpicoxIntroduction to web programming for java and c# programmers by @drpicox
Introduction to web programming for java and c# programmers by @drpicoxDavid Rodenas
 
DjangoCon US 2011 - Monkeying around at New Relic
DjangoCon US 2011 - Monkeying around at New RelicDjangoCon US 2011 - Monkeying around at New Relic
DjangoCon US 2011 - Monkeying around at New RelicGraham Dumpleton
 
Redux for ReactJS Programmers
Redux for ReactJS ProgrammersRedux for ReactJS Programmers
Redux for ReactJS ProgrammersDavid Rodenas
 
Clojure - A new Lisp
Clojure - A new LispClojure - A new Lisp
Clojure - A new Lispelliando dias
 
Final JAVA Practical of BCA SEM-5.
Final JAVA Practical of BCA SEM-5.Final JAVA Practical of BCA SEM-5.
Final JAVA Practical of BCA SEM-5.Nishan Barot
 
The Ring programming language version 1.8 book - Part 9 of 202
The Ring programming language version 1.8 book - Part 9 of 202The Ring programming language version 1.8 book - Part 9 of 202
The Ring programming language version 1.8 book - Part 9 of 202Mahmoud Samir Fayed
 
Inside PyMongo - MongoNYC
Inside PyMongo - MongoNYCInside PyMongo - MongoNYC
Inside PyMongo - MongoNYCMike Dirolf
 
ES3-2020-06 Test Driven Development (TDD)
ES3-2020-06 Test Driven Development (TDD)ES3-2020-06 Test Driven Development (TDD)
ES3-2020-06 Test Driven Development (TDD)David Rodenas
 

What's hot (20)

Grails/Groovyによる開発事例紹介
Grails/Groovyによる開発事例紹介Grails/Groovyによる開発事例紹介
Grails/Groovyによる開発事例紹介
 
Celery
CeleryCelery
Celery
 
Spock Framework
Spock FrameworkSpock Framework
Spock Framework
 
Unit Testing with Foq
Unit Testing with FoqUnit Testing with Foq
Unit Testing with Foq
 
Spock
SpockSpock
Spock
 
Advanced Java Practical File
Advanced Java Practical FileAdvanced Java Practical File
Advanced Java Practical File
 
DCN Practical
DCN PracticalDCN Practical
DCN Practical
 
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
 
Core java pract_sem iii
Core java pract_sem iiiCore java pract_sem iii
Core java pract_sem iii
 
Java 7 LavaJUG
Java 7 LavaJUGJava 7 LavaJUG
Java 7 LavaJUG
 
Software Testing - Invited Lecture at UNSW Sydney
Software Testing - Invited Lecture at UNSW SydneySoftware Testing - Invited Lecture at UNSW Sydney
Software Testing - Invited Lecture at UNSW Sydney
 
Introduction to web programming for java and c# programmers by @drpicox
Introduction to web programming for java and c# programmers by @drpicoxIntroduction to web programming for java and c# programmers by @drpicox
Introduction to web programming for java and c# programmers by @drpicox
 
Java practical
Java practicalJava practical
Java practical
 
DjangoCon US 2011 - Monkeying around at New Relic
DjangoCon US 2011 - Monkeying around at New RelicDjangoCon US 2011 - Monkeying around at New Relic
DjangoCon US 2011 - Monkeying around at New Relic
 
Redux for ReactJS Programmers
Redux for ReactJS ProgrammersRedux for ReactJS Programmers
Redux for ReactJS Programmers
 
Clojure - A new Lisp
Clojure - A new LispClojure - A new Lisp
Clojure - A new Lisp
 
Final JAVA Practical of BCA SEM-5.
Final JAVA Practical of BCA SEM-5.Final JAVA Practical of BCA SEM-5.
Final JAVA Practical of BCA SEM-5.
 
The Ring programming language version 1.8 book - Part 9 of 202
The Ring programming language version 1.8 book - Part 9 of 202The Ring programming language version 1.8 book - Part 9 of 202
The Ring programming language version 1.8 book - Part 9 of 202
 
Inside PyMongo - MongoNYC
Inside PyMongo - MongoNYCInside PyMongo - MongoNYC
Inside PyMongo - MongoNYC
 
ES3-2020-06 Test Driven Development (TDD)
ES3-2020-06 Test Driven Development (TDD)ES3-2020-06 Test Driven Development (TDD)
ES3-2020-06 Test Driven Development (TDD)
 

Viewers also liked

Spock Framework 2
Spock Framework 2Spock Framework 2
Spock Framework 2Ismael
 
Groovier testing with Spock
Groovier testing with SpockGroovier testing with Spock
Groovier testing with SpockRobert Fletcher
 
Testing Storm components with Groovy and Spock
Testing Storm components with Groovy and SpockTesting Storm components with Groovy and Spock
Testing Storm components with Groovy and SpockEugene Dvorkin
 
Vert.x 세미나 이지원_배포용
Vert.x 세미나 이지원_배포용Vert.x 세미나 이지원_배포용
Vert.x 세미나 이지원_배포용지원 이
 
A Gentle Introduction To Docker And All Things Containers
A Gentle Introduction To Docker And All Things ContainersA Gentle Introduction To Docker And All Things Containers
A Gentle Introduction To Docker And All Things ContainersJérôme Petazzoni
 
Java Testing With Spock - Ken Sipe (Trexin Consulting)
Java Testing With Spock - Ken Sipe (Trexin Consulting)Java Testing With Spock - Ken Sipe (Trexin Consulting)
Java Testing With Spock - Ken Sipe (Trexin Consulting)jaxLondonConference
 
UX, ethnography and possibilities: for Libraries, Museums and Archives
UX, ethnography and possibilities: for Libraries, Museums and ArchivesUX, ethnography and possibilities: for Libraries, Museums and Archives
UX, ethnography and possibilities: for Libraries, Museums and ArchivesNed Potter
 
3 Things Every Sales Team Needs to Be Thinking About in 2017
3 Things Every Sales Team Needs to Be Thinking About in 20173 Things Every Sales Team Needs to Be Thinking About in 2017
3 Things Every Sales Team Needs to Be Thinking About in 2017Drift
 

Viewers also liked (10)

Spock Framework 2
Spock Framework 2Spock Framework 2
Spock Framework 2
 
Groovier testing with Spock
Groovier testing with SpockGroovier testing with Spock
Groovier testing with Spock
 
Testing Storm components with Groovy and Spock
Testing Storm components with Groovy and SpockTesting Storm components with Groovy and Spock
Testing Storm components with Groovy and Spock
 
Spring puzzlers
Spring puzzlersSpring puzzlers
Spring puzzlers
 
Vert.x 세미나 이지원_배포용
Vert.x 세미나 이지원_배포용Vert.x 세미나 이지원_배포용
Vert.x 세미나 이지원_배포용
 
A Gentle Introduction To Docker And All Things Containers
A Gentle Introduction To Docker And All Things ContainersA Gentle Introduction To Docker And All Things Containers
A Gentle Introduction To Docker And All Things Containers
 
Docker by Example - Basics
Docker by Example - Basics Docker by Example - Basics
Docker by Example - Basics
 
Java Testing With Spock - Ken Sipe (Trexin Consulting)
Java Testing With Spock - Ken Sipe (Trexin Consulting)Java Testing With Spock - Ken Sipe (Trexin Consulting)
Java Testing With Spock - Ken Sipe (Trexin Consulting)
 
UX, ethnography and possibilities: for Libraries, Museums and Archives
UX, ethnography and possibilities: for Libraries, Museums and ArchivesUX, ethnography and possibilities: for Libraries, Museums and Archives
UX, ethnography and possibilities: for Libraries, Museums and Archives
 
3 Things Every Sales Team Needs to Be Thinking About in 2017
3 Things Every Sales Team Needs to Be Thinking About in 20173 Things Every Sales Team Needs to Be Thinking About in 2017
3 Things Every Sales Team Needs to Be Thinking About in 2017
 

Similar to Smarter Testing with Spock

Fun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksFun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksMongoDB
 
BDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
BDD - Behavior Driven Development Webapps mit Groovy Spock und GebBDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
BDD - Behavior Driven Development Webapps mit Groovy Spock und GebChristian Baranowski
 
Introduction to-mongo db-execution-plan-optimizer-final
Introduction to-mongo db-execution-plan-optimizer-finalIntroduction to-mongo db-execution-plan-optimizer-final
Introduction to-mongo db-execution-plan-optimizer-finalM Malai
 
Introduction to Mongodb execution plan and optimizer
Introduction to Mongodb execution plan and optimizerIntroduction to Mongodb execution plan and optimizer
Introduction to Mongodb execution plan and optimizerMydbops
 
A piece of sugar in your client-side development
A piece of sugar in your client-side developmentA piece of sugar in your client-side development
A piece of sugar in your client-side developmentNicolas Blanco
 
Rapid and Scalable Development with MongoDB, PyMongo, and Ming
Rapid and Scalable Development with MongoDB, PyMongo, and MingRapid and Scalable Development with MongoDB, PyMongo, and Ming
Rapid and Scalable Development with MongoDB, PyMongo, and MingRick Copeland
 
G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門Tsuyoshi Yamamoto
 
Front End Development: The Important Parts
Front End Development: The Important PartsFront End Development: The Important Parts
Front End Development: The Important PartsSergey Bolshchikov
 
More Data, More Problems: Evolving big data machine learning pipelines with S...
More Data, More Problems: Evolving big data machine learning pipelines with S...More Data, More Problems: Evolving big data machine learning pipelines with S...
More Data, More Problems: Evolving big data machine learning pipelines with S...Alex Sadovsky
 
Rx for Android & iOS by Harin Trivedi
Rx for Android & iOS  by Harin TrivediRx for Android & iOS  by Harin Trivedi
Rx for Android & iOS by Harin Trivediharintrivedi
 
4Developers: Michał Szczepanik- Kotlin - Let’s ketchup it
4Developers: Michał Szczepanik- Kotlin - Let’s ketchup it4Developers: Michał Szczepanik- Kotlin - Let’s ketchup it
4Developers: Michał Szczepanik- Kotlin - Let’s ketchup itPROIDEA
 
What's new in Python 3.11
What's new in Python 3.11What's new in Python 3.11
What's new in Python 3.11Henry Schreiner
 
What's New In Python 2.6
What's New In Python 2.6What's New In Python 2.6
What's New In Python 2.6Richard Jones
 
Building Apps with MongoDB
Building Apps with MongoDBBuilding Apps with MongoDB
Building Apps with MongoDBNate Abele
 
Exploring Clojurescript
Exploring ClojurescriptExploring Clojurescript
Exploring ClojurescriptLuke Donnet
 
ES3-2020-P3 TDD Calculator
ES3-2020-P3 TDD CalculatorES3-2020-P3 TDD Calculator
ES3-2020-P3 TDD CalculatorDavid Rodenas
 

Similar to Smarter Testing with Spock (20)

Play!ng with scala
Play!ng with scalaPlay!ng with scala
Play!ng with scala
 
Fun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksFun Teaching MongoDB New Tricks
Fun Teaching MongoDB New Tricks
 
Why ruby
Why rubyWhy ruby
Why ruby
 
BDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
BDD - Behavior Driven Development Webapps mit Groovy Spock und GebBDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
BDD - Behavior Driven Development Webapps mit Groovy Spock und Geb
 
Introduction to-mongo db-execution-plan-optimizer-final
Introduction to-mongo db-execution-plan-optimizer-finalIntroduction to-mongo db-execution-plan-optimizer-final
Introduction to-mongo db-execution-plan-optimizer-final
 
Introduction to Mongodb execution plan and optimizer
Introduction to Mongodb execution plan and optimizerIntroduction to Mongodb execution plan and optimizer
Introduction to Mongodb execution plan and optimizer
 
A piece of sugar in your client-side development
A piece of sugar in your client-side developmentA piece of sugar in your client-side development
A piece of sugar in your client-side development
 
Rapid and Scalable Development with MongoDB, PyMongo, and Ming
Rapid and Scalable Development with MongoDB, PyMongo, and MingRapid and Scalable Development with MongoDB, PyMongo, and Ming
Rapid and Scalable Development with MongoDB, PyMongo, and Ming
 
G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門
 
Front End Development: The Important Parts
Front End Development: The Important PartsFront End Development: The Important Parts
Front End Development: The Important Parts
 
More Data, More Problems: Evolving big data machine learning pipelines with S...
More Data, More Problems: Evolving big data machine learning pipelines with S...More Data, More Problems: Evolving big data machine learning pipelines with S...
More Data, More Problems: Evolving big data machine learning pipelines with S...
 
Scala coated JVM
Scala coated JVMScala coated JVM
Scala coated JVM
 
Rx for Android & iOS by Harin Trivedi
Rx for Android & iOS  by Harin TrivediRx for Android & iOS  by Harin Trivedi
Rx for Android & iOS by Harin Trivedi
 
4Developers: Michał Szczepanik- Kotlin - Let’s ketchup it
4Developers: Michał Szczepanik- Kotlin - Let’s ketchup it4Developers: Michał Szczepanik- Kotlin - Let’s ketchup it
4Developers: Michał Szczepanik- Kotlin - Let’s ketchup it
 
What's new in Python 3.11
What's new in Python 3.11What's new in Python 3.11
What's new in Python 3.11
 
What's New In Python 2.6
What's New In Python 2.6What's New In Python 2.6
What's New In Python 2.6
 
Building Apps with MongoDB
Building Apps with MongoDBBuilding Apps with MongoDB
Building Apps with MongoDB
 
Specs2
Specs2Specs2
Specs2
 
Exploring Clojurescript
Exploring ClojurescriptExploring Clojurescript
Exploring Clojurescript
 
ES3-2020-P3 TDD Calculator
ES3-2020-P3 TDD CalculatorES3-2020-P3 TDD Calculator
ES3-2020-P3 TDD Calculator
 

Smarter Testing with Spock

  • 2. What we’ll talk about Spock?! State Based Testing Data Driven Testing Interaction Based Testing Spock Extensions More Cool Stuff
  • 4. Spock is... A developer testing framework... for Groovy and Java applications... based on Groovy... fully compatible with JUnit... but going beyond!
  • 5. Spock Can... Reduce the lines of test code Make tests more readable Turn tests into specifications Be extended in powerful ways Bring back the fun to testing!
  • 6. Getting Started Homepage http://spockframework.org Source Code https://github.com/spockframework/spock Spock Web Console http://meet.spockframework.org Spock Example Project http://downloads.spockframework.org https://github.com/spockframework/spock/tree/groovy-1.8/spock- example
  • 7. Who’s Using Spock? Gradle GPars Grails Geb Grails Plugin Collective Apache Tapestry Griffon Spock Spring?
  • 8. Who’s Using Spock? Betfair be2 bemoko BSkyB CTI Digital Donewtech Solutions eHarmony Energized Work Gennemtænkt IT IntelliGrape Software Netflix Smarter Ecommerce STERMEDIA Sp. z o.o. Software Projects Spot Diving SystemsForge TouK
  • 10. State Based Testing Classical Unit Testing Arrange Act Assert Given-When-Then
  • 11. The Code For Testing Account.java public class Account { private BigDecimal balance = new BigDecimal(0); public Account(BigDecimal initial) { balance = initial; } public BigDecimal getBalance() { return balance; } public void withdraw(BigDecimal amount) { if (amount.compareTo(BigDecimal.ZERO) < 0) { throw new NegativeAmountWithdrawnException(amount); } balance = balance.subtract(amount); } }
  • 12. The Code For Testing NegativeAmountWithdrawnException.java public class NegativeAmountWithdrawnException extends RuntimeException { private final BigDecimal amount; public NegativeAmountWithdrawnException(BigDecimal amount) { super("cannot withdraw" + amount); this.amount = amount; } public BigDecimal getAmount() { return amount; } }
  • 13. Show me the code public class AccountTest { @Test public void withdrawSomeAmount() { // given Account account = new Account(BigDecimal.valueOf(5)); // when account.withdraw(BigDecimal.valueOf(2)); // then assertEquals(BigDecimal.valueOf(3), account.getBalance()); } }
  • 14. Show me the code class AccountSpec extends Specification { def "withdraw some amount"() { given: Account account = new Account(BigDecimal.valueOf(5)); when: account.withdraw(BigDecimal.valueOf(2)); then: account.getBalance() == BigDecimal.valueOf(3); } }
  • 15. Show me the code class AccountSpec2 extends Specification { def "withdraw some amount"() { given: def account = new Account(5.0) when: account.withdraw(2.0) then: account.balance == 3.0 } }
  • 16. Show me the code class AccountSpec3 extends Specification { def "withdraw some amount"() { given: "an account with a balance of five euros" def account = new Account(5.0) when: "two euros are withdrawn" account.withdraw(2.0) then: "three euros remain in the account" account.balance == 3.0 } }
  • 17. Show me the code class AccountSpec4 extends Specification { def "can't withdraw a negative amount"() { given: def account = new Account(5.0) when: account.withdraw(-1.0) then: NegativeAmountWithdrawnException e = thrown() e.amount == -1.0 } def "withdrawing some amount decreases the balance by exactly that amount"() { def account = new Account(5.0) when: account.withdraw(2.0) then: account.balance == old(account.balance) - 2.0 } }
  • 18. Show me the code class SharedField extends Specification { @Shared File file def "a file based test"() { when: file = new File("foo.txt") file.createNewFile() then: file.exists() } def "by now the object is not null"() { expect: file.exists() cleanup: file.delete() } }
  • 19. Show me the code class SetupSpecSpec extends Specification { File file def setup() { file = new File("foo2.txt") } def "a file based test"() { when: file.createNewFile() then: file.exists() } def "by now the object is not null"() { expect: file.exists() cleanup: file.delete() } }
  • 20. Show me the code class Conditions extends Specification { def "when-then style"() { when: def x = Math.max(5, 9) then: x == 9 } def "expect style"() { expect: Math.max(5, 9) == 9 } def "more complex conditions"() { expect: germanCarBrands.any { it.size() >= 3 } } private getGermanCarBrands() { ["audi", "bmw", "porsche"] } }
  • 21. Recap: State Based Testing Blocks setup: cleanup: expect: given: when: then: where: and: Fixture Methods setup() cleanup() setupSpec() cleanupSpec() Instance and @Shared fields old() and thrown()
  • 23. Data Driven Testing Test the same behavior... with varying data!
  • 24. Show me the code class AccountSpecDataDriven extends Specification { @Unroll def "withdraw some amount"() { given: def account = new Account(balance) when: account.withdraw(withdrawn) then: account.balance == remaining where: balance | withdrawn | |remaining 5.0 | 2.0 | | 3.0 4.0 | 0.0 | | 4.0 4.0 | 4.0 | | 0.0 } }
  • 25. Show me the code class AccountSpecDataDriven extends Specification { @Unroll def "withdrawing #withdrawn from account with balance #balance"() { given: def account = new Account(balance) when: account.withdraw(withdrawn) then: account.balance == old(account.balance) – withdrawn where: balance | withdrawn 5.0 | 2.0 4.0 | 0.0 4.0 | 4.0 } }
  • 26. Show me the code class AccountSpecDatabaseDriven extends Specification { @Shared sql = Sql.newInstance("jdbc:h2:mem:", "org.h2.Driver") def setupSpec() { sql.execute("create table accountdata (id int primary key, balance decimal, withdrawn decimal, remaining decimal)") sql.execute("insert into accountdata values (1, 5.0, 2.0, 3.0), (2, 4.0, 0.0, 4.0), (3, 4.0, 4.0, 0.0)") } @Unroll def "withdrawing #withdrawn from account with balance #balance leaves #remaining"() { given: def account = new Account(balance) when: account.withdraw(withdrawn) then: account.balance == remaining where: [balance, withdrawn, remaining] << sql.rows("select balance, withdrawn, remaining from accountdata") } }
  • 27. Recap: Data Driven Testing where: block Data tables External data sources @Unroll
  • 29. Interaction Based Testing Design and test how your objects communicate Mocking frameworks to the rescue Spock comes with its own mocking framework
  • 30. The Code For Testing PublisherSubscriber.groovy interface Subscriber { void receive(String message) } class Publisher { List<Subscriber> subscribers = [] void publish(String message) { for (subscriber in subscribers) { try { subscriber.receive(message) } catch (ignored) {} } } }
  • 31. The Code For Testing PublisherSubscriber.groovy interface Subscriber2 { void receive(String message) boolean isActive() } class Publisher2 { List<Subscriber2> subscribers = [] void publish(String message) { for (subscriber in subscribers) { try { if (subscriber.active) { subscriber.receive(message) } } catch (ignored) {} } } }
  • 32. Show me the code class PublisherSubscriberSpec extends Specification { def pub = new Publisher() def sub1 = Mock(Subscriber) def sub2 = Mock(Subscriber) def setup() { pub.subscribers << sub2 << sub1 } def "delivers messages to all subscribers"() { when: pub.publish("msg") then: 1 * sub1.receive("msg") 1 * sub2.receive("msg") } }
  • 33. Show me the code class PublisherSubscriberSpec2 extends Specification { def pub = new Publisher() def sub1 = Mock(Subscriber) def setup() { pub.subscribers << sub1 } def "delivers messages in the order they are published"() { when: pub.publish("msg1") pub.publish("msg2") then: 1 * sub1.receive("msg1") then: 1 * sub1.receive("msg2") } }
  • 34. Show me the code class PublisherSubscriber2Spec extends Specification { def pub = new Publisher2() def sub1 = Mock(Subscriber2) def sub2 = Mock(Subscriber2) def setup() { pub.subscribers << sub1 << sub2 } def "delivers messages to all active subscribers"() { sub1.active >> true sub2.active >> false when: pub.publish("msg") then: 1 * sub1.receive("msg") 0 * sub2.receive(_) } }
  • 35. Recap: Interaction Based Testing Creating def sub = Mock(Subscriber) Subscriber sub = Mock() Mocking 1 * sub.receive("msg") (1..3) * sub.receive(_) (1.._) * sub.receive(_ as String) 1 * sub.receive(!null) 1 * sub.receive({it.contains("m")}) 1 * _./rec.*/("msg")
  • 36. Recap: Interaction Based Testing Stubbing // now returns status code String receive(String msg) { ... } sub.receive(_) >> "ok" sub.receive(_) >>> ["ok", "ok", "fail"] sub.receive(_) >>> { msg -> msg.size() > 3 ? "ok" : "fail" } Mocking and Stubbing 3 * sub.receive(_) >>> ["ok", "ok", "fail"] Impressing your friends (_.._) * _._(*_) >> _
  • 40. Show me the code class JUnitRules extends Specification { @Rule TemporaryFolder tempFolder @Shared File file def "a file based test"() { when: file = tempFolder.newFile("foo.txt") then: file.exists() } def "by now the file has been deleted"() { expect: !file.exists() } }
  • 41. Show me the code @Stepwise class StepwiseSpec extends Specification { def "step 1"() { expect: true } def "step 2"() { expect: true } def "step 3"() { expect: true } }
  • 44. Grails Extensions @TestFor(MouthService) @Mock([Patient, PatientMouth, PatientTooth]) class MouthServiceSpec extends Specification { def "Get patient tooth by index"() { setup: "Create domain mocks" def patient = new Patient(dateOfBirth: new Date('05/03/1984')).save(false) def patientTooth = new PatientTooth(index: 10, toothCode: "10").save(false) def patientMouth = new PatientMouth(patient: patient, patientTeeth: [patientTooth]).save(false) when: patientTooth = service.getPatientToothByIndex(patientMouth, index) then: patientTooth.toothCode == tooth patientMouth.patientTeeth.contains(patientTooth) where: index | tooth 10 | "10" 20 | null } }
  • 45. Spring Extension class InjectionExamples extends Specification { @Autowired Service1 byType @Resource Service1 byName @Autowired ApplicationContext context }
  • 47. Configuring Spock ~/.spock/SpockConfig.groovy, or on class path, or with -Dspock.configuration runner { filterStackTrace false include Fast exclude Slow optimizeRunOrder true } @Fast class MyFastSpec extends Specification { def "I’m fast as hell!"() { expect: true } @Slow def “Sorry, can’t keep up..."() {expect: false } }
  • 48. Tooling Eclipse, IDEA Ant, Maven, Gradle Jenkins, Bamboo, TeamCity Spock runs everywhere JUnit and Groovy run!
  • 49. Spock Under The Hood You write... a = 1; b = 2; c = 4 expect: sum(a, b) == c Spock generates... def rec = new ValueRecorder() verifier.expect( rec.record(rec.record(sum(rec.record(a), rec.record(b)) == rec.record(c))) You see... sum (a, b) == c | | | | | 3 1 2 | 4 false
  • 50. Q&A Homepage http://spockframework.org Source Code https://github.com/spockframework/spock Spock Web Console http://meet.spockframework.org Spock Example Project http://downloads.spockframework.org https://github.com/spockframework/spock/tree/groovy-1.8/spock-example