© Adam L. Davis 2019
Adam L. DavisLearning Groovy 3https://doi.org/10.1007/978-1-4842-5058-7_14

14. Spock

Adam L. Davis1 
(1)
New York, NY, USA
 
Spock1 is a testing framework for Java and Groovy applications that takes full advantage of Groovy and has object mocking integrated. The Spock web site2 has this to say about Spock:
  • Spock is a testing and specification framework for Java and Groovy applications. What makes it stand out from the crowd is its beautiful and highly expressive specification language. Thanks to its JUnit runner, Spock is compatible with most IDEs, build tools, and continuous integration servers. Spock is inspired from JUnit, RSpec, jMock, Mockito, Groovy, Scala, Vulcans, and other fascinating life forms.

Spock Basics

The basic structure of a test class in Spock is a class that extends spock.lang.Specification and has multiple test methods (which may have descriptive String names).

Spock processes the test code and allows you to use a simple Groovy syntax to specify tests.

Each test is composed of labeled blocks of code with labels like when, then, and where. The best way to learn Spock is with examples.

To get started, first add Spock as a dependency to your project. For example, within a Gradle build file, put the following:
1   dependencies {
2    testCompile "org.spockframework:spock-core:1.3-groovy-2.5"
3   }

A Simple Test

Let’s start by recreating a simple test:
1   def "toString yields the String representation"() {
2           def array = ['a', 'b', 'c'] as String[]
3           when:
4           def arrayWrapper = new ArrayWrapper<>(array)
5           then:
6           arrayWrapper.toString() == '[a, b, c]'
7   }

As shown, assertions are simply groovy conditional expressions. If the == expression returns false, the test will fail and Spock will give a detailed printout to explain why it failed.

In the absence of any when clause , you can use the expect clause instead of then; for example:
1   def "empty list size is zero"() {
2           expect: [].size() == 0
3   }

Mocking

Mocking interfaces is extremely easy in Spock.3 Simply use the Mock method, as shown in the following example (where Subscriber is an interface):
1   class  APublisher  extends  Specification {
2     def  publisher = new  Publisher()
3     def subscriber = Mock(Subscriber)
Now subscriber is a mocked object. You can implement methods simply using the overloaded >> operator as shown next. The following example throws an Exception whenever receive is called:
1   def "can cope with misbehaving subscribers"() {
2       subscriber.receive(_) >> { throw   new   Exception() }
3
4       when:
5       publisher.send("event")
6       publisher.send("event")
7
8       then:
9       2 * subscriber.receive("event")
10   }

The expected behavior can be described by using a number or range multiplied by (*) the method call, as shown here. This means to expect this method is called two times; otherwise the test will fail.

The underscore (_) is treated like a wildcard much like in Scala (here the _ is just a field that refers to an object defined by Spock).

Lists or Tables of Data

Much like how JUnit has DataPoints and Theories, Spock allows you to use lists or tables of data in tests.

For example:
1   def "subscribers receive published events at least once"(){
2       when: publisher.send(event)
3       then: (1.._) * subscriber.receive(event)
4       where: event << ["started", "paused", "stopped"]
5   }

The overloaded << operator is used to provide a list for the event variable. Although it is a list here, anything that is Iterable could be used. This has the effect of running the test for each value in the list.

Ranges

The range 1.._ here means “one or more” times. You can also use _..3, for example, to mean “three or fewer” times.

Tabular formatted data can be used as well. For example:
1   def "length of NASA mission names"() {
2         expect:
3         name.size() == length
4
5         where:
6         name       | length
7         "Mercury"  | 7
8         "Gemini"   | 6
9         "Apollo"   | 6
10   }

In this case, the two columns (name and length) are used to substitute the corresponding variables in the expect block. Any number of columns can be used.

Expecting Exceptions

Use the "thrown" method in the then block to expect a thrown Exception.
1   def "peek on empty stack throws"() {
2       when: stack.peek()
3       then: thrown(EmptyStackException)
4   }
You can also capture the thrown Exception by simply assigning it to thrown(). For example:
1   def "peek on empty stack throws"() {
2       when: stack.peek()
3       then:
4       Exception e = thrown()
5       e.toString().contains("EmptyStackException")
6   }

Summary

As you can see, Spock makes tests more concise and easy to read, includes mocking built-in, and, most importantly, makes the intentions of the test clear.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset