Lately, I've been playing around with embedding Mule in Tomcat. To get going, I wanted to start with creating an extermely simple service, and along the way I decided to try out the Spock specification framework to test the logic I'd be using in my service. I liked what I found so much, I thought I'd take a little detour and write about my first use of the framework, comparing it to more a common test class, and save the Tomcat posting for another day.

The simple service that will eventually be developed will take a list of numbers and add them up. Here is the class that will ultimately do the math:

`class Adder {`

Integer add(List<Integer> numbers) {

println "adding: $numbers"

numbers.inject(0) { sum, item -> sum + item }

}

}

The **add** method takes a list of numbers and returns their sum. I'm using **Integer** as the return type and **List** on the parameter declaration instead of the **def** keyword to aid in the generation of the service WSDL down the line. While the **println** won't make into the final version of the class, it might help us out demonstrating what is being sent to the method during testing.

With **Spock** we'll be writing a specification that describes the behavior of the **Adder** class:

- Given a list of numbers, they should be added together to produce a sum.
- Given a list containg no numbers, zero should be returned.

The framework's documentation does a great job explaining how to write a spec, so I will not to try and reproduce much of it here. The spec is pretty much self-explanatory, each of the two requirements manifests itself in a method:

`import spock.lang.*`

class AdderSpec extends Specification {

def adder = new Adder()

def "numbers should be added together to produce a sum"() {

expect:

sum == adder.add(numbers)

where:

sum | numbers

4 | [2, 2]

6 | [1, 2, 3]

10 | [1, 2, 3, 4]

1 | [0, 1]

0 | [0, 0]

}

def "summing no numbers at all should return zero"() {

expect:

sum == adder.add(numbers)

where:

sum | numbers

0 | []

0 | null

}

}

The **where** clauses resemble a table, with each entry describing the input to the add() method on the right, and the expected result on the left. The first entry in the first method would have the values for **sum** and **numbers** substituted into the **expect** clause so that it would read:

4 == adder.add([2, 2])

The output from the test run helps illustrate how things are added during a run of the spec:

Running org.prystasj.services.adder.AdderSpec

adding: [2, 2]

adding: [1, 2, 3]

adding: [0, 1]

adding: []

adding: null

Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.091 sec

If the value for **numbers** instead read **[2, 3]**, we would get the following failure when we run the test as 2+3 does not equal 4:

Condition not satisfied:

sum == adder.add(numbers)

| | | | |

4 | | 5 [2, 3]

| org.prystasj.services.adder.Adder@969c29

false

While I could of used a helper method to remove the redunduncy between the two **expect** clauses, I liked this output such much, I decided to keep it, as using a method here would modify the resulting failure description. For example:

check(sum, numbers)

| | |

false 4 [2, 3]

Compare the above spec class to a more traditional unit test and see what you think:

`import org.junit.Before`

import org.junit.Test

import static org.junit.Assert.assertEquals

class AdderTest {

def underTest

@Before

void setUp() {

underTest = new Adder()

}

def verifySumsFor(data) {

data.each { sum, numbers ->

assertEquals "$sum <= $numbers", sum, underTest.add(numbers)

}

}

@Test

void test_numbers_added_together_produce_a_sum() {

def data = [

4 : [2, 2],

6 : [1, 2, 3],

10 : [1, 2, 3, 4],

1 : [0, 1],

0 : [0, 0],

]

verifySumsFor(data)

}

@Test

void test_summing_no_numbers_at_all_should_return_zero() {

def data = [

0 : [],

0 : null,

]

verifySumsFor(data)

}

}

Which version do you like better? Thanks for reading.

Nice blog post. You can get the same condition output in helper methods like so:

ReplyDeletevoid check(sum, numbers) {

assert sum == adder.add(numbers)

}

However, this mostly makes sense when you keep repeating a whole bunch of conditions.

Hello John

ReplyDeleteI'm working with Mule and liking very much what I'm reading about Spock. Did you manage to have something equivalent to Mule's FunctionalTrestCase with Spock?

Thanks for your time!