Using spock data table for filling objects
Asked Answered
N

3

7

I am using Spock for the first time. Since we are using a complex domain-model it would be handy to have a mechanism, which allows me to create full objects from data given by spock tables. I do not want to give all values each time, I just want to set the values in defined in datable. So there should be defined default values somewhere.

Yes, I know I could write on my own, but maybe there is an out-of-the-box solution.

Example

class A {
   String name
   int age
}

spock table

id | givenA                     | ...
1  | [name: "Michael"]          | ...
2  | [name: "Thomas", age: 45 ] | ...
  1. => A.name = "Michael", A.age = defined default somewhere
  2. => A.name = "Thomas" A.age = 45 (because I overwrite default value)
Newmark answered 2/10, 2014 at 7:57 Comment(2)
@Opal: Its a long way to forget the ";" in the end of a line. Thank you for removing it :-)Rugen
Yeah, beginnings are always difficult ;)Arreola
C
17

In every project I have, I create what I call 'UnitTestUtils' and this class mostly contains helper methods that create domain objects with default values and allow for overrides of those values. For example:

    Person createTestPerson(Map overrides = [:]){
        Person p = new Person(name: "Jim Bob", age: 45)
        overrides.each { String key, value ->
            if(p.hasProperty(key)){
                p.setProperty(key, value)
            } else {
                println "Error: Trying to add property that doesn't exist"
            }
        }
        return p
    }

Then you can make use of this method in your class by creating a map in the same way you've already done.

    void "my test"(){
        given:
            Person person
        when:
            person = UnitTestUtils.createTestPerson(givenA)
        then:
            person.name == expected.name
            person.age == expected.age
        where:
          id| givenA        | expected
          1 | [name: "Joe"] | [name: "Joe", age: 45]
          2 | [age: 5]      | [name: "Jim Bob", age: 5]
    }

It's not a built in Spock feature, but it should provide nicely for the use case you have specified.

Cluny answered 15/10, 2014 at 4:26 Comment(3)
I am new to groovy. This solution would overwrite each field automatically. I do not need to extend it for a new property?Rugen
In my example, you would be creating a new Person object with each call to "createTestPerson(givenA)." Passing givenA to the method and providing key/value pairs that match the field names of your object will simply replace any field specified in the map, with the value specified in the map. You don't need to extend anything since you are just passing the map to the method that returns a Person.Cluny
Additionally, @EhmKa, instead of using a class, you could just use a Map. It would have the same effect.Cluny
A
1

Basically there's no such mechanism You're looking for. If You need to provide default values for some objects/fields You need to do it Yourself and there's nothing strange, bad or unusual about it. Remember that the quality of test code is as important as the production code and it's not a bad practice to create some helper code that is used for tests only (of course this code exists only in tests hierarchy).

In this particular case instead of creating A class You can use Map.withDefault construct, but IMO using a dedicated class is much better.

Arreola answered 2/10, 2014 at 8:7 Comment(2)
What a pity. But I have to make some experiments with spock to find a good trade of. I Already wrote some factories, which use maps to create full Domain Objects.Rugen
I don't know the scenario well but after some thinking I guess a simple map will be most powerful. If You're satisfied with the answer please accept it.Arreola
P
0

Not sure what exactly you are looking for, but instead of [name: "Thomas", age: 45], you can write new A(name: Thomas, age: 45). If you want to reuse fixtures, you can do:

where:
[id, givenA] << staticUtilityMethodThatReturnsCollectionOfTwoElementCollections()

You can also create a small API (or use Groovy's built-in collection operations) to modify the defaults.

Pomander answered 2/10, 2014 at 10:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.