2013-03-06 31 views
7

Tôi đang cố gắng đơn vị kiểm tra một dịch vụ có một phương thức yêu cầu một đối tượng yêu cầu.Làm thế nào để thử một yêu cầu khi đơn vị thử nghiệm một dịch vụ trong grails

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

Bạn thử đối tượng yêu cầu bằng cách nào?

Và nhân tiện, tôi đang sử dụng Spock để kiểm tra đơn vị lớp học của mình.

Cảm ơn bạn

Trả lời

5

Một cách đơn giản để nhạo báng này, là để sửa đổi các lớp meta cho RequestContextHolder để trả về một giả khi getRequestAttributes() được gọi.

Tôi đã viết một thông số kỹ thuật đơn giản để thực hiện việc này và khá ngạc nhiên khi nó không hoạt động! Vì vậy, điều này hóa ra lại là một vấn đề khá thú vị. Sau một số cuộc điều tra, tôi thấy rằng trong trường hợp đặc biệt này, có một vài cạm bẫy cần lưu ý.

  1. Khi bạn lấy đối tượng yêu cầu, RCH.requestAttributes.request, bạn đang làm như vậy thông qua một giao diện RequestAttributes mà không thực hiện phương pháp getRequest(). Điều này là hoàn toàn tốt trong groovy nếu đối tượng trả về thực sự có thuộc tính này, nhưng sẽ không hoạt động khi chế nhạo giao diện RequestAttributes trong spock. Vì vậy, bạn sẽ cần phải giả lập một giao diện hoặc một lớp thực sự có phương pháp này.

  2. Lần đầu tiên tôi giải quyết 1., là thay đổi loại mô hình thành ServletRequestAttributes, có phương thức getRequest(). Tuy nhiên, phương pháp này là cuối cùng. Khi bố trí một mô hình với các giá trị cho một phương thức cuối cùng, các giá trị gốc được bỏ qua. Trong trường hợp này, null đã được trả lại.

Cả hai vấn đề này dễ dàng khắc phục bằng cách tạo giao diện tùy chỉnh cho thử nghiệm này, được gọi là MockRequestAttributes và sử dụng giao diện này cho Mô hình trong thông số.

Điều này dẫn đến đoạn mã sau:

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 
    } 

} 
3

Mã này dường như làm việc cho một thử nghiệm đơn vị cơ bản (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) 
} 

Nó có thể được thêm vào như một hàm cho phép thử đơn vị Grails tiêu chuẩn của bạn vì tên hàm không bắt đầu bằng "test" ... hoặc bạn có thể làm việc theo cách khác.

Các vấn đề liên quan