如何在Ratpack中使用RequestFixture模拟会话? [英] How do I mock a Session in Ratpack with RequestFixture?

查看:95
本文介绍了如何在Ratpack中使用RequestFixture模拟会话?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

What I'm trying to do is test an authentication handler, but my problem boils down to having no Session instance in the registry.

示例测试:

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测试中抛出的异常,因为默认情况下它是被捕获并藏在结果中的.)

(The extra rethrow is in there to allow us to see the exception thrown within the ratpack test, because by default it is caught and stashed in the result.)

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

I know that in principle I could create a Session instance and add it to the registry with a registry { add <Session instance> } block, but I've delved into the Ratpack code, and creating a Session object requires getting a lot of disparate other components and passing them to SessionModule#sessionAdaptor (or the DefaultSession constructor). I can't find any examples of that being done, it appears this call is handled by Guice dependency-injection magic I can't unpick.

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

The usual way to do it in an application is to use a bind { module SessionModule } block but this isn't accessible from the context of RequestFixture#execute.

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

As sessions are bread and butter for any web application, my hunch is that this may be an easily solved problem, I just haven't found the right way to do it?

推荐答案

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

You can access Registry through GroovyRequestFixture.handle(handler, closure) method call and you can e.g. register mocked Session object:

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']

    }
}

在此测试中,我模拟了键testSession对象以存储Lorem ipsum文本.运行此测试时,两个断言均会通过.

In this test I mock Session object for key test to store Lorem ipsum text. When running this test, both assertions pass.

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

If you don't want to use mocked Session object you can try replacing default Ratpack's Registry with a Guice registry object. Firstly, initialize a function that creates Guice registry and add SessionModule via bindings:

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

下一步,在GroovyChainActionexecute()方法中,您可以通过调用以下内容来替换默认注册表:

Next inside execute() method of GroovyChainAction you can replace the default registry by calling:

register(guiceRegistry.apply(registry))

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

No mocks anymore, but in this case you can't access Session object outside request scope, so you wont be able to add anything to the session in preparation stage of your test. Below you can find full example:

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]

    }
}

希望有帮助.

这篇关于如何在Ratpack中使用RequestFixture模拟会话?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆