Your SlideShare is downloading. ×
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Smarter Testing With Spock
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Smarter Testing With Spock

2,841

Published on

by Dmitry Voloshko …

by Dmitry Voloshko

What we’ll talk about
Spock?!
State Based Testing
Data Driven Testing
Interaction Based Testing
Spock Extensions
More Cool Stuff

1 Comment
8 Likes
Statistics
Notes
  • I have looked a numerous presentations on Spock, and yours was the best. Many thanks for sharing.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total Views
2,841
On Slideshare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
69
Comments
1
Likes
8
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Smarter Testing With Spock Dmitry Voloshko 03/11/2012
  • 2. What we’ll talk aboutSpock?!State Based TestingData Driven TestingInteraction Based TestingSpock ExtensionsMore Cool Stuff
  • 3. Spock?!
  • 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 codeMake tests more readableTurn tests into specificationsBe extended in powerful waysBring back the fun to testing!
  • 6. Getting StartedHomepagehttp://spockframework.orgSource Codehttps://github.com/spockframework/spockSpock Web Consolehttp://meet.spockframework.orgSpock Example Projecthttp://downloads.spockframework.orghttps://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 eHarmonyEnergized Work Gennemtænkt IT IntelliGrape Software NetflixSmarter Ecommerce STERMEDIA Sp. z o.o. Software Projects Spot Diving SystemsForge TouK
  • 9. State Based Testing
  • 10. State Based TestingClassical Unit Testing Arrange Act AssertGiven-When-Then
  • 11. The Code For TestingAccount.javapublic 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 TestingNegativeAmountWithdrawnException.javapublic 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 codepublic 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 codeclass 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 codeclass 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 codeclass 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 codeclass AccountSpec4 extends Specification { def "cant 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 codeclass 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 codeclass 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 codeclass 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 TestingBlockssetup: cleanup: expect: given: when: then:where: and:Fixture Methodssetup() cleanup() setupSpec() cleanupSpec()Instance and @Shared fieldsold() and thrown()
  • 22. Data Driven Testing
  • 23. Data Driven TestingTest the same behavior...with varying data!
  • 24. Show me the codeclass 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 codeclass 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 codeclass 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 Testingwhere: blockData tablesExternal data sources@Unroll
  • 28. Interaction Based Testing
  • 29. Interaction Based TestingDesign and test how your objectscommunicateMocking frameworks to the rescueSpock comes with its own mockingframework
  • 30. The Code For TestingPublisherSubscriber.groovyinterface 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 TestingPublisherSubscriber.groovyinterface 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 codeclass 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 codeclass 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 codeclass 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 (_.._) * _._(*_) >> _
  • 37. Spock Extensions
  • 38. Spock ExtensionsListenersInterceptorsAnnotation-driven extensionsGlobal extensions
  • 39. Built-in Extensions@Ignore@IgnoreRest@FailsWith@Timeout@AutoCleanup@Stepwise@RevertMetaClass@Rule
  • 40. Show me the codeclass 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@Stepwiseclass StepwiseSpec extends Specification { def "step 1"() { expect: true } def "step 2"() { expect: true } def "step 3"() { expect: true }}
  • 42. External Extensionsspock-grailsspock-springspock-guicespock-tapestryspock-unitilsspock-griffonspock-arquillianspock-extensions http://github.com/robfletcher/spock-extensions
  • 43. Grails Extensionshttp://grails.org/plugin/spockhttps://github.com/spockframework/spock-grailsgrails install plugin spock 0.6grails test-appgrails test-app unit:TestSpec
  • 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 Extensionclass InjectionExamples extends Specification { @Autowired Service1 byType @Resource Service1 byName @Autowired ApplicationContext context}
  • 46. Other Cool Stuff
  • 47. Configuring Spock~/.spock/SpockConfig.groovy, or on class path, or with -Dspock.configurationrunner { filterStackTrace false include Fast exclude Slow optimizeRunOrder true}@Fastclass MyFastSpec extends Specification { def "I’m fast as hell!"() { expect: true } @Slow def “Sorry, can’t keep up..."() {expect: false }}
  • 48. ToolingEclipse, IDEAAnt, Maven, GradleJenkins, Bamboo, TeamCitySpock runs everywhere JUnit and Groovy run!
  • 49. Spock Under The HoodYou write...a = 1; b = 2; c = 4expect: sum(a, b) == cSpock 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 12 | 4 false
  • 50. Q&AHomepagehttp://spockframework.orgSource Codehttps://github.com/spockframework/spockSpock Web Consolehttp://meet.spockframework.orgSpock Example Projecthttp://downloads.spockframework.orghttps://github.com/spockframework/spock/tree/groovy-1.8/spock-example

×