Ben Green
Ben Green

Reputation: 4111

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?

Upvotes: 8

Views: 9369

Answers (1)

Ben Green
Ben Green

Reputation: 4111

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"]
    }
}

Upvotes: 7

Related Questions