Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MissingPropertyException thrown in spock test where block

I have been using spock for a while to unit test my java project, and have ran into a problem. I have a utility method to get a parameter from a http request, or an empty string if the http request is null and am trying to test it with spock. My test looks like this:

package foo.bar.test

import foo.bah.HttpRequestPropertyLoader
import spock.lang.Unroll
import javax.servlet.http.HttpServletRequest
import spock.lang.Specification

class HttpRequestPropertyLoaderTest extends Specification {

    HttpRequestPropertyLoader subjectUnderTest
    def result

    def setup() {
        subjectUnderTest = new HttpRequestPropertyLoader()
    }

    @Unroll("When my http request is #nullOrNot then when I get parameter from it the response=#response" )
    def "Test load data from request"() {
        given:
        HttpServletRequest mockHttpRequest = Mock()
        mockHttpRequest.getAttribute("foo") >> "bar"
        when:
        result = subjectUnderTest.loadStringFromHttpRequest(httpRequest, "foo")
        then:
        result == response
        where:
        httpRequest     | response | nullOrNot
        null            |  ""      | "null"
        mockHttpRequest | "bar"    | "not null"
    }
}

However, when I run this test, I get the following error:

groovy.lang.MissingPropertyException: No such property: mockHttpRequest for class: foo.bar.test.HttpRequestPropertyLoaderTest at foo.bar.test.HttpRequestPropertyLoaderTest.Test load data from request(HttpRequestPropertyLoaderTest.groovy)

After doing some research, I understand that the where block is run before the given block, hence the error, but was just wondering if there was a workaround?

I know that to use a variable from outside the test, I would need to annotate the variable with the @Shared annotation, which seems bad practice to me. Every test should run completely separate from the others, so don't really want to have an object that keeps it's state between tests.

Is it possible to setup Mock objects to be returned from the where block any other way?

like image 223
Ben Green Avatar asked Jul 17 '15 10:07

Ben Green


1 Answers

Following tim_yates suggestion to take a look at https://code.google.com/p/spock/issues/detail?id=15#c4, I found a fairly elegant solution that doesn't involve using the @Shared annotation. The test definition now looks like this:

package foo.bar.test

import foo.bah.HttpRequestPropertyLoader
import spock.lang.Unroll
import javax.servlet.http.HttpServletRequest
import spock.lang.Specification

class HttpRequestPropertyLoaderTest extends Specification {

    HttpRequestPropertyLoader subjectUnderTest
    def result

    def setup() {
        subjectUnderTest = new HttpRequestPropertyLoader()
    }

    @Unroll("When my http request is #nullOrNot then when I get parameter from it the response=#response" )
    def "Test load data from request"() {
        when:
        result = subjectUnderTest.loadStringFromHttpRequest(httpRequest, "foo")
        then:
        result == response
        where:
        httpRequest << {
            HttpServletRequest mockHttpRequest = Mock()
            mockHttpRequest.getAttribute("foo") >> "bar"
            [null, mockHttpRequest]
        }()
        response << ["", "bar"]
        nullOrNot << ["null", "not null"]
    }
}
like image 164
Ben Green Avatar answered Sep 19 '22 02:09

Ben Green