1

我要做的是测试身份验证处理程序,但我的问题归结Session为注册表中没有实例。

一个示例测试:

package whatever

import groovy.transform.CompileStatic
import ratpack.groovy.handling.GroovyChainAction
import ratpack.groovy.test.handling.GroovyRequestFixture
import ratpack.http.Status
import ratpack.session.Session
import spock.lang.Specification

class SessionChainTest extends Specification {
    GroovyChainAction sessionChain = new GroovyChainAction() {
        @Override
        @CompileStatic
        void execute() throws Exception {
            get('foo') {
                Session s = get Session
                // Stuff using session here
            }
        }
    }

    def "should get session"() {
        given:
        def result = GroovyRequestFixture.handle(sessionChain) {
            uri 'foo'
            method 'GET'
        }

        expect:
        result.status == Status.OK

        // If the server threw, rethrow that
        Throwable t = result.exception(Throwable)
        if (t) throw t // <<< Throws NotInRegistryException because no Session in registry
    }

}

(额外的重新抛出是为了让我们看到在ratpack测试中抛出的异常,因为默认情况下它会被捕获并隐藏在结果中。)

我知道原则上我可以创建一个 Session 实例并使用一个registry { add <Session instance> }块将其添加到注册表中,但是我已经深入研究了 Ratpack 代码,并且创建一个 Session 对象需要获取许多不同的其他组件并将它们传递给SessionModule#sessionAdaptor(或DefaultSession构造函数)。我找不到任何这样做的例子,看来这个调用是由 Guice 依赖注入魔法处理的,我无法解开。

在应用程序中执行此操作的常用方法是使用bind { module SessionModule }块,但这不能从RequestFixture#execute.

由于会话是任何 Web 应用程序的生计,我的直觉是这可能是一个容易解决的问题,我只是没有找到正确的方法吗?

4

1 回答 1

1

您可以Registry通过GroovyRequestFixture.handle(handler, closure)方法调用访问,例如注册模拟Session对象:

GroovyRequestFixture.handle(sessionChain) {
    uri 'foo'
    method 'GET'
    registry { r ->
        r.add(Session, session)
    }
}

看看下面的例子:

import groovy.transform.CompileStatic
import ratpack.exec.Promise
import ratpack.groovy.handling.GroovyChainAction
import ratpack.groovy.test.handling.GroovyRequestFixture
import ratpack.http.Status
import ratpack.jackson.internal.DefaultJsonRender
import ratpack.session.Session
import spock.lang.Specification

import static ratpack.jackson.Jackson.json

class SessionChainTest extends Specification {

    Session session = Mock(Session) {
        get('test') >> Promise.value(Optional.of('Lorem ipsum'))
    }

    GroovyChainAction sessionChain = new GroovyChainAction() {
        @Override
        @CompileStatic
        void execute() throws Exception {
            get('foo') {
                Session s = get Session

                s.get('test').map { Optional<String> o ->
                    o.orElse(null)
                }.flatMap { value ->
                    Promise.value(value)
                }.then {
                    render(json([message: it]))
                }
            }
        }
    }

    def "should get session"() {
        given:
        def result = GroovyRequestFixture.handle(sessionChain) {
            uri 'foo'
            method 'GET'
            registry { r ->
                r.add(Session, session)
            }
        }

        expect:
        result.status == Status.OK

        and:
        result.rendered(DefaultJsonRender).object == [message: 'Lorem ipsum']

    }
}

在这个测试中,我模拟Session对象以test获取存储Lorem ipsum文本的键。运行此测试时,两个断言都通过了。

替代方法:注册Guice.registry()

如果您不想使用模拟Session对象,您可以尝试用RegistryGuice 注册表对象替换默认的 Ratpack。首先,初始化一个创建 Guice 注册表并SessionModule通过绑定添加的函数:

static Function<Registry, Registry> guiceRegistry = Guice.registry { bindings ->
    bindings.module(new SessionModule())
}

您可以通过调用以下execute()方法GroovyChainAction替换默认注册表:

register(guiceRegistry.apply(registry))

不再模拟,但在这种情况下,您无法访问Session请求范围之外的对象,因此您将无法在测试的准备阶段向会话添加任何内容。您可以在下面找到完整示例:

import groovy.transform.CompileStatic
import ratpack.exec.Promise
import ratpack.func.Function
import ratpack.groovy.handling.GroovyChainAction
import ratpack.groovy.test.handling.GroovyRequestFixture
import ratpack.guice.Guice
import ratpack.http.Status
import ratpack.jackson.internal.DefaultJsonRender
import ratpack.registry.Registry
import ratpack.session.Session
import ratpack.session.SessionModule
import spock.lang.Specification

import static ratpack.jackson.Jackson.json

class SessionChainTest extends Specification {

    static Function<Registry, Registry> guiceRegistry = Guice.registry { bindings ->
        bindings.module(new SessionModule())
    }

    GroovyChainAction sessionChain = new GroovyChainAction() {
        @Override
        @CompileStatic
        void execute() throws Exception {
            register(guiceRegistry.apply(registry))

            get('foo') {
                Session s = get Session

                s.get('test').map { Optional<String> o ->
                    o.orElse(null)
                }.flatMap { value ->
                    Promise.value(value)
                }.then {
                    render(json([message: it]))
                }
            }
        }
    }

    def "should get session"() {
        given:
        def result = GroovyRequestFixture.handle(sessionChain) {
            uri 'foo'
            method 'GET'
        }

        expect:
        result.status == Status.OK

        and:
        result.rendered(DefaultJsonRender).object == [message: null]

    }
}

希望能帮助到你。

于 2018-06-12T11:04:50.337 回答