模拟这些的一种简单方法是修改元类以在调用RequestContextHolder
时返回模拟。getRequestAttributes()
我为此编写了一个简单的规范,当它不起作用时,我感到非常惊讶!所以这是一个非常有趣的问题。经过一番调查,我发现在这种特殊情况下,有几个陷阱需要注意。
当您检索请求对象时RCH.requestAttributes.request
,您是通过一个RequestAttributes
未实现该getRequest()
方法的接口来执行此操作的。RequestAttributes
如果返回的对象实际上具有此属性,这在 groovy 中非常好,但在 spock 中模拟接口时将不起作用。因此,您需要模拟一个实际具有此方法的接口或类。
我第一次尝试解决 1.,是将模拟类型更改为ServletRequestAttributes
,它确实有一个getRequest()
方法。然而,这个方法是最终的。当使用最终方法的值存根模拟时,存根值将被简单地忽略。在这种情况下,null
被退回。
通过为此测试创建一个名为 的自定义接口MockRequestAttributes
,并在规范中将此接口用于 Mock,这两个问题都可以轻松克服。
这导致了以下代码:
import org.springframework.web.context.request.RequestContextHolder
// modified for testing
class AddressService {
def localAddress
def contentType
def update() {
def request = RequestContextHolder.requestAttributes.request
localAddress = request.localAddr
contentType = request.contentType
}
}
import org.springframework.web.context.request.RequestAttributes
import javax.servlet.http.HttpServletRequest
interface MockRequestAttributes extends RequestAttributes {
HttpServletRequest getRequest()
}
import org.springframework.web.context.request.RequestContextHolder
import spock.lang.Specification
import javax.servlet.http.HttpServletRequest
class MockRequestSpec extends Specification {
def "let's mock a request"() {
setup:
def requestAttributesMock = Mock(MockRequestAttributes)
def requestMock = Mock(HttpServletRequest)
RequestContextHolder.metaClass.'static'.getRequestAttributes = {->
requestAttributesMock
}
when:
def service = new AddressService()
def result = service.update()
then:
1 * requestAttributesMock.getRequest() >> requestMock
1 * requestMock.localAddr >> '127.0.0.1'
1 * requestMock.contentType >> 'text/plain'
service.localAddress == '127.0.0.1'
service.contentType == 'text/plain'
cleanup:
RequestContextHolder.metaClass = null
}
}