Как правильно переместить вспомогательные методы модульного теста Grails в отдельный файл? - PullRequest
7 голосов
/ 12 мая 2011

У меня есть несколько часто используемых вспомогательных методов для модульных тестов, помещенных в отдельный файл. Идея состоит в том, чтобы, например, разрешить моему XYZTests.groovy вызывать TestHelper.getUserObject (), чтобы получить полностью инициализированный экземпляр User.

Теперь проблема в том, что springSecurityService.encodePassword(pw) вызывается в пользовательском beforeInsert(), который всегда терпит неудачу, поскольку не имеет значения для springSecurityService в TestHelper.groovy.

java.lang.NullPointerException: Cannot invoke method encodePassword() on null object

In User.groovy :

def beforeInsert() {
    // ...
    password = springSecurityService.encodePassword(pw)
    // ...
}

Примечание: я хотел бы избежать насмешек в TestHelper.groovy, чтобы использовать его методы и в интеграционных тестах.

Несмотря на это, , даже если Я пытаюсь вызвать mockFor() в любом месте TestHelper.groovy, я получаю MME:

No signature of method: static myproject.TestHelper.mockFor() is applicable for argument types: (java.lang.Class, java.lang.Boolean) values: [class grails.plugins.springsecurity.SpringSecurityService, true]
groovy.lang.MissingMethodException: No signature of method: static myproject.TestHelper.mockFor() is applicable for argument types: (java.lang.Class, java.lang.Boolean) values: [class grails.plugins.springsecurity.SpringSecurityService, true]
    at myproject.TestHelper.mockSpringSecurityService(TestHelper.groovy:59)
    at myproject.TestHelper$mockSpringSecurityService.callStatic(Unknown Source)
    at myproject.TestHelper.getUserObject(TestHelper.groovy:47)
    at myproject.TestHelper$getUserObject.call(Unknown Source)
    at myproject.UserTests.setUp(UserTests.groovy:26)

Примечание: В настоящее время я издеваюсь над springSecurityService.encodePassword следующим образом:

// in UserTests.groovy
protected void setUp() {
    // mockDomain(...) and such here

    def u = TestHelper.getUserObject("Pummel")
    u.springSecurityService = mockSpringSecurityService()
    assert u.save()
}
private mockSpringSecurityService() {
    def ssService = mockFor(SpringSecurityService,true)
    ssService.metaClass.encodePassword() { password ->
        "08a2d3c63bf9fc88276d97a9e8df5f841fd772724ad10f119f7e516f228b74c6"
    }

    ssService
}
  1. Есть идеи о том, как я могу использовать вспомогательный класс, оставляя все насмешки только в юнит-тестах?
  2. Где лучше всего разместить файл TestHelper.groovy для его использования в интеграционных И модульных тестах?

Обратите внимание, что все работает отлично, когда я перемещаю всех помощников непосредственно в UserTests.groovy!

Ответы [ 2 ]

5 голосов
/ 24 мая 2011

Решением этой проблемы является воздержание от вызова любого user.save() в TestHelper.groovy .

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

С другой стороны, во многих случаях требуется несохраненный экземпляр. (Например, для проверки некоторых эффектов самого .save())

Рабочий пример для интеграционных тестов будет:

def user = TestHelper.getUserObject()
user.save()

Для модульных тестов:

def user = TestHelper.getUserObject()
user.springSecurityService = new SpringSecurityService() // or the described mock accordingly
user.save()

Это исключает любые насмешки из TestHelper.groovy

2 голосов
/ 12 мая 2011
  1. В вашем TestHelper вы можете использовать Groovy ExpandoMetaClass metaClass.static, чтобы добавить фиктивное закрытие для encodePassword в SpringSecurityService:

    SpringSecurityService.metaClass.'static'.encodePassword = {'08a2d3c63bf9fc88276d97a9e8df5f841fd772724ad10f119f7e516f228b74c6'}
    
  2. Я бы вставил этот класс в тестовый пакет под src / groovy

...