【问题标题】:How to mock a request when unit testing a service in grails在 Grails 中对服务进行单元测试时如何模拟请求
【发布时间】:2013-02-21 22:47:54
【问题描述】:

我正在尝试对具有需要请求对象的方法的服务进行单元测试。

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 */ 
        }
    }
}

你如何模拟请求对象?

顺便说一句,我正在使用 Spock 对我的课程进行单元测试。

谢谢

【问题讨论】:

    标签: unit-testing grails groovy spock


    【解决方案1】:

    此代码似乎适用于基本单元测试 (modified from Robert Fletcher's post here):

    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”开头...或者您可以以其他方式处理代码。

    【讨论】:

      【解决方案2】:

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

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-16
        相关资源
        最近更新 更多