smarter-testing-with-spock



smarter-testing-with-spock

0 0


smarter-testing-with-spock

Intro presentation for Spock

On Github stigkj / smarter-testing-with-spock

Smarter testing with Spock

Why Spock?

Spock can...

  • reduce the lines of test code
    • removes noise with concise syntax
  • make tests more readable (structural blocks)
  • be extended in powerful ways
  • be run like JUnit test (good tool support)

Parameterization

IntelliJ formats data table correctly

class MathSpec extends Specification {
    @Issue('REIS-325')
    @Unroll
    def "max of #x and #y should be #result"() {
      when:
        def max = Math.max(x, y)

      then:
        max == result
        notThrown(IllegalStateException)

      where:
        x | y | result
        1 | 3 | 3
        4 | 2 | 4
    }
}

Parameterization

Nice result rendering

maximum of 3 and 5 is 5   PASSED
maximum of 7 and 0 is 7   FAILED

Math.max(a, b) == c
    |    |  |  |  |
    |    7  0  |  7
    42         false

maximum of 0 and 0 is 0   PASSED

Problems when comparing

input == 42
|     |
|     false
42

Problems when comparing

input == 42
|     |
|     false
42 (java.lang.String)

Utilities for testing async code

then:
  new PollingConditions() {
    assert flightResultPage.numberOfChildren == 100
  }

Mocking setup

Publisher publisher
Subscriber sub1
Subscriber sub2

def setup() {
    publisher = new Publisher()
    sub1 = Mock()
    sub2 = Mock()
    publisher.subscribers << sub1 << sub2
}

Mocking/stubbing

@Timeout(123)
def 'mocking_stubbing'() {
  given: 'sub2 which throws exception on 2. call when input too long'
    sub2.receive(_) >> 'ok' >>
      { msgs -> msgs[0].size() > 4 ? throw new ISE() : 'ok' }

  when: 'publishing events'
    publisher.send(event)

  then: 'exception is thrown after second call of publisher.send(...)'
    (1.._) * _./rec.*/({ it.contains('s') })
    IllegalStateException e = thrown()
    e.message == 'Subscriber failed'

  where:
    event << ['test', 'fails']
}

Both at the same time

@IgnoreRest
def 'both'() {
  given: 'sub2 which is called at least twice'
  and: 'returns an error status when input too long'
    (2.._) * sub2.receive(_) >>
       { msgs -> msgs[0].size() > 4 ? 'fail' : 'ok' }

Improve readability of tests

def 'improve_readability'() {
  given: '...'
    ...
  and: '...'
    ...

  when: '...'
    ...
  and: '...'
    ...

  then: '...'
    ...
  and: '...'
    ...
}