Unit testing spock测试中抛出MissingPropertyException,其中块

Unit testing spock测试中抛出MissingPropertyException,其中块,unit-testing,groovy,spock,Unit Testing,Groovy,Spock,我已经使用spock对我的java项目进行了一段时间的单元测试,但遇到了一个问题。我有一个实用程序方法可以从http请求中获取参数,如果http请求为null并且正在尝试使用spock测试它,则可以获取空字符串。我的测试如下所示: package foo.bar.test import foo.bah.HttpRequestPropertyLoader import spock.lang.Unroll import javax.servlet.http.HttpServletRequest i

我已经使用spock对我的java项目进行了一段时间的单元测试,但遇到了一个问题。我有一个实用程序方法可以从http请求中获取参数,如果http请求为null并且正在尝试使用spock测试它,则可以获取空字符串。我的测试如下所示:

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"
    }
}
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"]
    }
}
但是,当我运行此测试时,出现以下错误:

groovy.lang.MissingPropertyException:没有这样的属性:mockHttpRequest for class:foo.bar.test.HttpRequestPropertyLoaderTest位于foo.bar.test.HttpRequestPropertyLoaderTest的类:foo.bar.test.HttpRequestPropertyLoaderTest(HttpRequestPropertyLoaderTest.groovy)

在做了一些研究之后,我了解到
where
块在
给定的
块之前运行,因此出现了错误,但我只是想知道是否有解决方法

我知道要在测试之外使用变量,我需要用
@Shared
注释对变量进行注释,这在我看来是一种糟糕的做法。每个测试都应该完全独立于其他测试运行,所以我不想让一个对象在测试之间保持它的状态


是否可以通过其他方式设置从where块返回的模拟对象?

根据tim_yates的建议,我找到了一个相当优雅的解决方案,它不需要使用
@Shared
注释。测试定义现在如下所示:

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"
    }
}
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"]
    }
}
package foo.bar.test
导入foo.bah.HttpRequestPropertyLoader
导入spock.lang.Unroll
导入javax.servlet.http.HttpServletRequest
导入spock.lang.Specification
类HttpRequestPropertyLoaderTest扩展了规范{
HttpRequestPropertyLoader主题测试
def结果
def设置(){
subjectUnderTest=新的HttpRequestPropertyLoader()
}
@展开(“当我的http请求为#nullOrNot时,当我从中获取参数时,响应=#响应”)
def“来自请求的测试负载数据”(){
什么时候:
结果=subjectUnderTest.loadStringFromHttpRequest(httpRequest,“foo”)
然后:
结果==响应
哪里:
httpRequest>“条”
[null,mockHttpRequest]
}()

响应您是否尝试过移动
HttpServletRequest mockHttpRequest=Mock()
到一个
设置
块开始测试时?@tim_yates谢谢你的建议。我刚刚尝试用一个设置块替换给定的块,如果这是你的意思,并得到了相同的结果。四处搜索,我想你需要将你的模拟类移出到一个
@共享
类级字段:@tim_yates是的,我看到了e
@Shared
注释之前,但正如其中一个答案所说,“缺点是a和o在某种意义上定义在错误的范围内,也可能被其他特性方法使用。”正如我在编辑中所说,这对我来说似乎是一种不好的做法,但如果没有其他选择,我将不得不研究它。我想你可能会移动b将为
httpRequest
创建模拟值列表的锁锁定到一个单独的
static
方法中,并且只在
where
块中调用它。然后它应该更干净、更可读,类似于
httpRequest它可以工作!非常好的回答:)