Как мне смоделировать сеанс в Ratpack с помощью RequestFixture? - PullRequest
0 голосов
/ 12 июня 2018

Я пытаюсь протестировать обработчик аутентификации, но моя проблема сводится к тому, что в реестре нет экземпляра 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
    }

}

(Дополнительный rethrow здесь, чтобы мы могли видеть исключение, выброшенное в тесте ratpack, потому что по умолчанию оно перехватывается и сохраняется в результате.)

Я знаю, что в принципе я мог бы создать Сессиюи добавьте его в реестр с помощью блока registry { add <Session instance> }, но я углубился в код Ratpack, и для создания объекта Session требуется получить множество разрозненных других компонентов и передать их в SessionModule#sessionAdaptor (или DefaultSessionконструктор).Я не могу найти никаких примеров того, как это делается, похоже, этот вызов обрабатывается магией внедрения зависимостей Guice, которую я не могу убрать.

Обычный способ сделать это в приложении - использовать *Блок 1014 *, но он недоступен из контекста RequestFixture#execute.

Поскольку сеансы - это хлеб с маслом для любого веб-приложения, я догадываюсь, что это может быть легко решаемой проблемой, я просто не знаю 'не нашли правильный способ сделать это?

1 Ответ

0 голосов
/ 12 июня 2018

Вы можете получить доступ к вызовам метода Registry через GroovyRequestFixture.handle(handler, closure) и, например, зарегистрировать mocked 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()

Если вы не хотите использовать mocked Session объект, вы можете попробовать заменить стандартный набор Ratpack Registry.с объектом реестра Guice.Во-первых, инициализируйте функцию, которая создает реестр 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]

    }
}

Надеюсь, это поможет.

...