Как протестировать службу Grails, извлекающую информацию из сеанса HTTP

Я пытаюсь написать тесты для веб-плагина Grails. Плагин содержит службу (UtilityService), которая имеет функцию getSession(), которая возвращает GrailsHttpSession. Другие службы используют это для чтения/записи значений в сеансе. Код работает нормально, но когда я пытаюсь написать тесты для любой функции, использующей возвращаемый объект сеанса, тесты терпят неудачу.

Моя цель на данный момент — просто написать тест, который доказывает, что утилитаService.getSession() что-то возвращает.

В настоящее время я работаю с Grails 3.2.7.

Утилиты:

package psu.util

import grails.transaction.Transactional
import grails.core.GrailsApplication
import grails.util.Environment

import grails.core.*
import org.grails.web.util.WebUtils
import org.springframework.web.context.request.RequestContextHolder
import javax.servlet.http.HttpServletRequest

@Transactional
class UtilityService {
    GrailsApplication grailsApplication

    @Transactional(readOnly = true)
    grails.web.servlet.mvc.GrailsHttpSession getSession(){
        return WebUtils.retrieveGrailsWebRequest()?.session
    }

}

Тест:

package psu.util

import grails.test.mixin.TestFor
import grails.test.mixin.integration.Integration
import grails.transaction.*
import spock.lang.*

@Integration
@Rollback
@TestFor(UtilityService)
class UtilityServiceIntegrationSpec extends Specification {

    def setup() {
    }

    def cleanup() {
    }

    void "test getSession"() {
        expect:
        service.getSession()
    }
}

Вывод теста:

Condition not satisfied:

service.getSession()
|       |
|       null
psu.util.UtilityService@28eab745

Вопросы. Нужно ли что-то сделать, чтобы сделать сеанс доступным в тестовой среде? Можно ли это сделать в модульном тесте или это должен быть интеграционный тест?


person Mike Gostomski    schedule 09.03.2017    source источник
comment
Не имеет отношения к вашему вопросу, но вам не нужна транзакция для получения сеанса, вы открываете соединение с БД и ничего не делаете с ним для своего getSession()   -  person erichelgeson    schedule 10.03.2017
comment
Нет веской причины, чтобы служба предоставляла метод getSession, который будут вызывать другие службы. Любая служба может реализовать grails.web.api.ServletAttributes, а затем в коде этой службы можно просто ссылаться на session.   -  person Jeff Scott Brown    schedule 10.06.2019


Ответы (2)


Самый простой способ — смоделировать метод getSession и вернуть макет сеанса (или Grails GrailsMockHttpSession), это просто, как в Groovy:

@TestFor(SessionService)
class SessionMockSpec extends Specification {

    GrailsHttpSession session

    def setup() {
        session = Mock()
        service.metaClass.getSession = { session }
    }

    def 'should return session'() {
        expect:
            service.getSession()
    }
person rgrebski    schedule 12.03.2017
comment
Это плохой ответ. Вопрос включает в себя Моя цель на данный момент - просто написать тест, который доказывает, что утилитаService.getSession() что-то возвращает. Решение, представленное в этом ответе, полностью избегает вызова тестируемого метода. Этот тест проверяет только тест, а не код службы. - person Jeff Scott Brown; 10.06.2019

Проект https://github.com/jeffbrown/mikegostomskiplugin демонстрирует один из способов сделать это.

https://github.com/jeffbrown/mikegostomskiplugin/blob/5dcb2953f1dc8eb20deefb26cdfa54e6f77617e6/grails-app/services/psu/util/UtilityService.groovy

package psu.util

import grails.web.api.ServletAttributes

class UtilityService implements ServletAttributes {

    def getSomethingFromSession(String key) {
        session[key]
    }
}

https://github.com/jeffbrown/mikegostomskiplugin/blob/5dcb2953f1dc8eb20deefb26cdfa54e6f77617e6/src/test/groovy/psu/util/UtilityServiceSpec.groovy

package psu.util

import grails.test.mixin.TestFor
import grails.test.mixin.TestMixin
import grails.test.mixin.web.ControllerUnitTestMixin
import spock.lang.Specification

@TestFor(UtilityService)
@TestMixin(ControllerUnitTestMixin)
class UtilityServiceSpec extends Specification {

    void 'test interacting with session'() {
        when:
        session.'Some Session Key' = 'King Crimson Is Awesome'

        then:
        service.getSomethingFromSession('Some Session Key') == 'King Crimson Is Awesome'
    }
}
person Jeff Scott Brown    schedule 10.06.2019
comment
реализует ServletAttributes, позволяя службам получать доступ к сеансу htto - person Pablo Pazos; 04.10.2019
comment
Правильно. Он предназначен для этого. Вот как контроллеры получают доступ к сеансу. Во время компиляции мы добавляем ServletAttributes во все классы контроллеров и публикуем трейт, чтобы вы могли использовать его в других классах по мере необходимости. - person Jeff Scott Brown; 05.10.2019