9

I am trying to unit test a service that has a method requiring a request object.

import org.springframework.web.context.request.RequestContextHolder as RCH

class AddressService {

    def update (account, params) {
        try {
            def request = RCH.requestAttributes.request
            // retrieve some info from the request object such as the IP ...
            // Implement update logic
        } catch (all) { 
            /* do something with the exception */ 
        }
    }
}

How do you mock the request object ?

And by the way, I am using Spock to unit test my classes.

Thank you

4

2 回答 2

8

此代码似乎适用于基本单元测试(从 Robert Fletcher 的帖子修改):

void createRequestContextHolder() {
    MockHttpServletRequest request = new MockHttpServletRequest()
    request.characterEncoding = 'UTF-8'

    GrailsWebRequest webRequest = new GrailsWebRequest(request, new MockHttpServletResponse(), ServletContextHolder.servletContext)
    request.setAttribute(GrailsApplicationAttributes.WEB_REQUEST, webRequest)

    RequestContextHolder.setRequestAttributes(webRequest)
}

它可以作为函数添加到您的标准 Grails 单元测试中,因为函数名称不以“test”开头......或者您可以以其他方式处理代码。

于 2013-07-11T00:31:28.747 回答
7

模拟这些的一种简单方法是修改元类以在调用RequestContextHolder时返回模拟。getRequestAttributes()

我为此编写了一个简单的规范,当它不起作用时,我感到非常惊讶!所以这是一个非常有趣的问题。经过一番调查,我发现在这种特殊情况下,有几个陷阱需要注意。

  1. 当您检索请求对象时RCH.requestAttributes.request,您是通过一个RequestAttributes未实现该getRequest()方法的接口来执行此操作的。RequestAttributes如果返回的对象实际上具有此属性,这在 groovy 中非常好,但在 spock 中模拟接口时将不起作用。因此,您需要模拟一个实际具有此方法的接口或类。

  2. 我第一次尝试解决 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
    }

}
于 2013-03-09T18:03:25.913 回答