tom bobby
tom bobby

Reputation: 59

Spock set list as parameter by using table

There is a simply class:

class Person {
   private int age;
   private String name;

   public String getName(){return this.name;}
   public int getAge(){return this.age;}
   public void setName(String name){this.name = name;}
   public void setAge(int age){this.age = age;}
 }

and I have a methods getPersonNameWithPrefix() and getPeopleNames() in SearchPeople interface with implement in SearchPeopleImpl:

class SearchPeopleImpl implements SearchPeople {

   public String getPersonNameWithPrefix(Person person){
      return "prefix" + person.getName();
   }

   public List<String> getPeopleNames(List<Person> peopleList){
      return peopleList.stream().map(Person::getName).collect(Collectors.toList());
   }

}

I want to use parameters in my test and it looks like:

def 'test Person name'(){
        given:
            def searchPeople = new SearchPeopleImpl ()
            def person = Mock(Person){
                getName() >> a
            }
        when:
            def name = searchPeople.getPersonNameWithPrefix(person)
        then:
            name == b
        where:
            a         |       b
            "AA"      |       "prefixAA"
            "BB"      |       "prefixBB"
            "CC"      |       "prefixCC"
    }

It works well but I have a problem with test my second method. How is it possible to put list of elements into table (in where section), use it as method parameter and then expect another list of objects? I mean that I want to declare a few list of Person objects and then check that method returns correct list of Strings

@UPDATE So is there any way to do something like:

   def 'test getting persons names'(){
        given:
            def searchPeople = new SearchPeopleImpl()
        when:
            def names = searchPeople.getPeopleNames(a)
        then:
            names == b
        where:
            a                                                                  |       b
            ["AA","BB"].collect{ x -> Mock(Person){ getName() >> x } }         |       [["AA", "BB"]]
            ["CC"].collect{ x -> Mock(Person){ getName() >> x } }              |       [["CC"]]
            ["DD","EE","FD"].collect{ x -> Mock(Person){ getName() >> x } }    |       [["DD","EE","FD"]]
    }

or:

def 'check double2 return value'(){
    given:
        def searchPeople = new SearchPeopleImpl()
    when:
        def names = searchPeople.getPeopleNames(a)
    then:
        names == b
    where:
        people1 << [
                ["AA","BB"].collect{ x ->
                    Mock(Person){
                        getName() >> x
                    }
                }
        ]
        people2 << [
                ["CC"].collect{ x ->
                    Mock(Person){
                        getName() >> x
                    }
                }
        ]

        names1 << [["AA", "BB"]]
        names2 << [["CC"]]

        a               |       b
        people1         |       names1
        people2         |       names2
}

I just want to use table to set parameters but it is possible that i am totally wrong.

@UPDATE there is an error:

check double return value[0](com.test.myPlugin.api.SearchPeopleSpec)  Time elapsed: 0.125 sec  <<< FAILURE!
Condition not satisfied:

names == b
|    |  |
|    |  [[AA, BB]]
|    false
[AA, BB]

and there is the same error for every row.

Upvotes: 1

Views: 5617

Answers (2)

Leonard Br&#252;nings
Leonard Br&#252;nings

Reputation: 13242

You can actually combine the data tables with variable assignments (docs) which provides a much cleaner test:

def 'test getting persons names'(){
    given:
    def searchPeople = new SearchPeopleImpl()

    when:
    def names = searchPeople.getPeopleNames(input)

    then:
    names == expected

    where:
    a                   |       expected
    ["AA","BB"]         |       [["AA", "BB"]]
    ["CC"]              |       [["CC"]]
    ["DD","EE","FD"]    |       [["DD","EE","FD"]]

    input = a.collect{ new Person(name: it) }
}

Furthermore, only use Mock if you need the validation, e.g., 1 * mock.method() if you only use it as a collaborator use Stub instead to make your intent clear. Also, never mock simple POJOs when you can just construct them via bean constructor.

Upvotes: 2

Opal
Opal

Reputation: 84844

An instance of List can be used in exactly the same way in data-drive testing. Have a look at the following example:

class PersonSpec extends Specification {

    def 'test getting persons names'() {
        given:
        def searchPeople = new SearchPeopleImpl()

        when:
        def result = searchPeople.getPeopleNames(names)

        then:
        result == expectedNames

        where:
        names << [
            ["AA", "BB"].collect { n ->
            Mock(Person) {
                getName() >> n
            }
        }
        ]
        expectedNames << [["AA", "BB"]]
    }
}

Note the double parens in where block. It must specified this way since if only single pair would be used every single argument will be passed separately instead of passing the whole list.

Upvotes: 3

Related Questions