Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Spocktacular Testing

Spocktacular Testing

My JAXLondon 2014 presentation on the Groovy testing framework Spock. Spock can be used with Java code as well as Groovy code and is just much better than TestNG and JUnit4.

Ca04455902d1b207348b6d406432718f?s=128

Russel Winder

October 14, 2014
Tweet

Transcript

  1. Copyright © 2014 Russel Winder 1 Spocktacular Testing Russel Winder

    email: russel@winder.org.uk xmpp: russel@winder.org.uk twitter: @russel_winder Web: http://www.russel.org.uk
  2. Copyright © 2014 Russel Winder 2 Opening

  3. Copyright © 2014 Russel Winder 3

  4. Copyright © 2014 Russel Winder 4 An Historical Perspective

  5. Copyright © 2014 Russel Winder 5 Spock sUnit TestNG JUnit

    GroovyTestCase jBehave RSpec JUnit4 BDD TDD
  6. Copyright © 2014 Russel Winder 6 Spock is Groovy-based… …but

    can test any JVM-based code.
  7. Copyright © 2014 Russel Winder 7 NB Testing frameworks support

    integration and system testing as well as unit testing.
  8. Copyright © 2014 Russel Winder 8

  9. Copyright © 2014 Russel Winder 9 Testing • Unit: •

    Test the classes, functions and methods to ensure they do what we need them to. • As lightweight and fast as possible. • Run all tests always. • Integration and system: • Test combinations or the whole thing to make sure the functionality is as required. • Separate process to create a sandbox . “ ” • If cannot run all tests always, create smoke tests.
  10. Copyright © 2014 Russel Winder 10 Code Under Test static

    message() { 'Hello World.' } println message() helloWorld.groovy
  11. Copyright © 2014 Russel Winder 11 Unit Test @Grab('org.spockframework:spock-core:0.7-groovy-2.0') import

    spock.lang.Specification import helloWorld class Test_HelloWorld extends Specification { def 'ensure the message function returns hello world'() { expect: helloWorld.message() == 'Hello World.' } }
  12. Copyright © 2014 Russel Winder 12 System Test @Grab('org.spockframework:spock-core:0.7-groovy-2.0') import

    spock.lang.Specification class Test_HelloWorld extends Specification { def 'executing the script results in hello world on the standard output'() { given: def process = 'helloWorld.groovy'.execute() expect: process.waitFor() == 0 process.in.text == 'Hello World.\n' } }
  13. Copyright © 2014 Russel Winder 13 A bit less Groovy…

  14. Copyright © 2014 Russel Winder 14 Code under Test package

    uk.org.winder.spockworkshop; class HelloWorld { private static String message() { return "Hello World."; } public static void main(final String[] args) { System.out.println(message()); } } HelloWorld.java
  15. Copyright © 2014 Russel Winder 15 Unit Test package uk.org.winder.spockworkshop

    import spock.lang.Specification class Test_HelloWorld extends Specification { def 'ensure the message function returns hello world'() { expect: HelloWorld.message() == 'Hello World.' } }
  16. Copyright © 2014 Russel Winder 16 Project Structure . ├──

    build.gradle └── src ├── main │ └── java │ └── uk │ └── org │ └── winder │ └── spockworkshop │ └─- HelloWorld.java └── test └── groovy └── uk └── org └── winder └── spockworkshop └── unitTest_helloWorld.groovy
  17. Copyright © 2014 Russel Winder 17 Build Gradle — apply

    plugin: 'groovy' apply plugin: 'application' repositories { mavenCentral() } dependencies { testCompile 'org.spockframework:spock-core:0.7-groovy-2.0' } mainClassName = 'uk.org.winder.spockworkshop.HelloWorld'
  18. Copyright © 2014 Russel Winder 18

  19. Copyright © 2014 Russel Winder 19 Moving On

  20. Copyright © 2014 Russel Winder 20

  21. Copyright © 2014 Russel Winder 21 Spock Test Structure

  22. Copyright © 2014 Russel Winder 22 given:

  23. Copyright © 2014 Russel Winder 23 Code Under Test static

    message() { 'Hello World.' } println message() helloWorld.groovy
  24. Copyright © 2014 Russel Winder 24 Unit Test @Grab('org.spockframework:spock-core:0.7-groovy-2.0') import

    spock.lang.Specification import helloWorld class Test_HelloWorld extends Specification { def 'ensure the message function returns hello world'() { expect: helloWorld.message() == 'Hello World.' } }
  25. Copyright © 2014 Russel Winder 25 Another Code Under Test

    class Stuff { private final data = [] def leftShift(datum) { data << datum } } Stuff.groovy
  26. Copyright © 2014 Russel Winder 26 Unit Testing It @Grab('org.spockframework:spock-core:0.7-groovy-2.0')

    import spock.lang.Specification import Stuff class TestStuff extends Specification { def 'check stuff'() { given: def stuff = new Stuff() expect: stuff.data == [] when: stuff << 6 then: stuff.data == [6] when: stuff << 6 then: stuff.data == [6, 6] } def 'check other stuff'() { given: def stuff = new Stuff() expect: stuff.data == [] when: stuff.leftShift(6) then: stuff.data == [6] when: stuff.leftShift(6) then: stuff.data == [6, 6] } }
  27. Copyright © 2014 Russel Winder 27

  28. Copyright © 2014 Russel Winder 28 Data-driven Testing

  29. Copyright © 2014 Russel Winder 29

  30. Copyright © 2014 Russel Winder 30 given:

  31. Copyright © 2014 Russel Winder 31 Code Under Test Id.groovy

    class Id { def eval(x) { x } }
  32. Copyright © 2014 Russel Winder 32 Unit Test Code #!

    /usr/bin/env groovy @Grab('org.spockframework:spock-core:0.7-groovy-2.0') import spock.lang.Specification import spock.lang.Unroll class idTest extends Specification { @Unroll def 'the id eval function always return the value of the parameter'() { given: final id = new Id () expect: id.eval(i) == i where: i << [0, 1, 2, 3, 's', 'ffff', 2.05] } }
  33. Copyright © 2014 Russel Winder 33 Code Under Test class

    Functions { static square(x) { x * x } } Functions.groovy
  34. Copyright © 2014 Russel Winder 34 Unit Test Variant 1

    — #! /usr/bin/env groovy @Grab('org.spockframework:spock-core:0.7-groovy-2.0') import spock.lang.Specification import spock.lang.Unroll class functionsTest_alt_1 extends Specification { @Unroll def 'square always returns the square of the numeric parameter'() { expect: Functions.square(x) == r where: x << [0, 1, 2, 3, 1.5] r << [0, 1, 4, 9, 2.25] } }
  35. Copyright © 2014 Russel Winder 35 Unit Test Variant 2

    — #! /usr/bin/env groovy @Grab('org.spockframework:spock-core:0.7-groovy-2.0') import spock.lang.Specification import spock.lang.Unroll class functionsTest_alt_1 extends Specification { @Unroll def 'square always returns the square of the numeric parameter'() { expect: Functions.square(x) == r where: [x, r] << [[0. 0], [1, 1], [2, 4], [3, 9], [1.5, 2.25]] } }
  36. Copyright © 2014 Russel Winder 36 Unit Test Tabular —

    #! /usr/bin/env groovy @Grab('org.spockframework:spock-core:0.7-groovy-2.0') import spock.lang.Specification import spock.lang.Unroll class functionsTest_alt_1 extends Specification { @Unroll def 'square always returns the square of the numeric parameter'() { expect: Functions.square(x) == r where: x | r 0 | 0 1 | 1 2 | 4 3 | 9 1.5 | 2.25 } }
  37. Copyright © 2014 Russel Winder 37 Exceptions

  38. Copyright © 2014 Russel Winder 38

  39. Copyright © 2014 Russel Winder 39 Code Under Test class

    Exceptional { def trySomething() { throw new RuntimeException('Stuff happens.') } } Exceptional.groovy
  40. Copyright © 2014 Russel Winder 40 Unit Test #! /usr/bin/env

    groovy @Grab('org.spockframework:spock-core:0.7-groovy-2.0') import spock.lang.Specification class ExceptionalTest extends Specification { def 'trying something always results in an exception'() { given: final e = new Exceptional () when: e.trySomething() then: thrown(RuntimeException) } }
  41. Copyright © 2014 Russel Winder 41 Now we can do

    data validation and testing of error situations.
  42. Copyright © 2014 Russel Winder 42

  43. Copyright © 2014 Russel Winder 43 Being More Adventurous

  44. Copyright © 2014 Russel Winder 44

  45. Copyright © 2014 Russel Winder 45 Spock sUnit TestNG JUnit

    GroovyTestCase jBehave RSpec JUnit4 BDD TDD
  46. Copyright © 2014 Russel Winder 46 Specify Behaviours 1/4 –

    @Grab('org.spockframework:spock-core:0.7-groovy-2.0') import spock.lang.Specification class StackSpecification extends Specification { def 'newly created stacks are empty'() { given: 'a newly created stack' expect: 'the resulting stack to be empty.' }
  47. Copyright © 2014 Russel Winder 47 def 'removing an item

    from a non-empty stack gives a value and changes the stack.'() { given: 'a new stack' and: 'an item to put on the stack' when: 'the item is added' then: 'the stack is not empty' when: 'an item is removed' then: 'the item we retrieved is the original and the stack is empty' } } Specify Behaviours 2/4 –
  48. Copyright © 2014 Russel Winder 48 Specify Behaviours 3/4 –

    @Grab('org.spockframework:spock-core:0.7-groovy-2.0') import spock.lang.Specification class StackSpecification extends Specification { def 'newly created stacks are empty'() { given: 'a newly created stack' def stack = new Stack () expect: 'the resulting stack to be empty.' stack.size() == 0 }
  49. Copyright © 2014 Russel Winder 49 def 'removing an item

    from a non-empty stack gives a value and changes the stack.'() { given: 'a new stack' def stack = new Stack () and: 'an item to put on the stack' def item = 25 and: 'a variable to store the result of activity' def result when: 'the item is added' stack.push(item) then: 'the stack is not empty' stack.size() == 1 when: 'an item is removed' result = stack.pop() then: 'the item we retrieved is the original and the stack is empty' result == item && stack.size() == 0 } } Specify Behaviours 4/4 –
  50. Copyright © 2014 Russel Winder 50

  51. Copyright © 2014 Russel Winder 51 Closing

  52. Copyright © 2014 Russel Winder 52 Hopefully everyone has had

    some fun and learnt some useful things.
  53. Copyright © 2014 Russel Winder 53

  54. Copyright © 2014 Russel Winder 54

  55. Copyright © 2014 Russel Winder 55

  56. Copyright © 2014 Russel Winder 56

  57. Copyright © 2014 Russel Winder 57 The End

  58. Copyright © 2014 Russel Winder 58 Spocktacular Testing Russel Winder

    email: russel@winder.org.uk xmpp: russel@winder.org.uk twitter: @russel_winder Web: http://www.russel.org.uk