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

7

これらをモックする簡単な方法の 1 つは、が呼び出されたRequestContextHolderときにモックを返すようにメタ クラスを変更することです。getRequestAttributes()

これを行うための簡単な仕様を書き上げましたが、うまくいかなかったときはかなり驚きました! したがって、これは非常に興味深い問題であることが判明しました。いくつかの調査の結果、この特定のケースでは、注意すべきいくつかの落とし穴があることがわかりました。

  1. リクエスト オブジェクトを取得するときは、メソッドを実装していないRCH.requestAttributes.requestインターフェイスを介して取得しています。返されたオブジェクトが実際にこのプロパティを持っている場合、これは groovy ではまったく問題ありませんが、spock でインターフェイスをモックする場合は機能しません。したがって、実際にこのメソッドを持つインターフェイスまたはクラスをモックする必要があります。RequestAttributesgetRequest()RequestAttributes

  2. 1. を解決するための私の最初の試みは、モック タイプをメソッドServletRequestAttributesを持つに変更することでしたgetRequest()。ただし、この方法は最終的なものです。final メソッドの値でモックをスタブ化すると、スタブ化された値は単純に無視されます。この場合、null返品されました。

これらの問題は両方とも、このテスト用に というカスタム インターフェースを作成し、MockRequestAttributesこのインターフェースを仕様のモックに使用することで簡単に克服できます。

これにより、次のコードが生成されました。

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 に答える