是否可以在同一单元测试中模拟控制器并访问 FormTagLib?
Is it possible to mock a controller and have access to the FormTagLib in the same unit test?
如标题所述,是否可以对控制器进行单元测试并模拟标签库?
就目前而言,我有一个用户控制器。许多动作使用
g.message(code: 'something.something')
调用以在页面上设置消息。
@TestFor(UserController)
@Mock(User)
@TestMixin(GroovyPageUnitTestMixin)
class UserControllerSpec extends Specification
{
UserService userServiceMock = Mock(UserService)
def setup()
{
controller.userService = userServiceMock
}
def cleanup()
{
}
void "test manageDevice"()
{
given:
def g = mockTagLib(FormTagLib)
when:
controller.manageDevice()
then:
model.pageTitle == 'message.device'
}
使用该代码,我试图点击控制器操作,但由于 g.message,它失败了,并显示一条错误消息,指出它无法将值设置为 null。几乎是因为它没有看到 "g.message"
我有点不确定我的单元测试是否需要以不同的方式编写,或者我是否只是遗漏了一些东西。
任何帮助都会很棒!
编辑:
使用 messageSource 的一些更新:
void "test manageDevice"()
{
given:
messageSource.addMessage 'user.devices', request.locale, 'Manage Devices'
when:
controller.manageDevices()
then:
assertEquals model.pageTitle == 'user.devices', controller.flash.message
}
它似乎还在抱怨,因为它在控制器上没有 "g" 命名空间的上下文。我还要注意,我没有来自 messageSource 的 'addMessage' 上下文。不知道为什么,它应该在那里。
在同一个控制器和许多其他控制器中,我们在控制器范围内使用的唯一标签库是 'g' 用于每个操作中的 'g.message' 集。唯一正在进行的其他调用是使用 'g' 进行调用,例如 'g.fixRedisIssue'
为什么不return消息代码而不是return将消息文本从控制器发送到视图?例如,如果您的视图中有这样的内容:
<p>${flash.message}</p>
您可以将其替换为:
<p><g:message code="${flash.code}" /></p>
然后在控制器中设置代码:
flash.code = "user.devices"
然后您将能够轻松地测试控制器方法:)
您可以通过在规范 class 上的 grails.test.mixin.Mock
注释的值中包含必要的 TagLib classes 来使用模拟的 TagLib 对控制器进行单元测试。例如,如果您有以下 TagLib:
(基于 Grails documentation 中的代码)
package org.grails.samples
class SimpleTagLib {
static namespace = 'g'
def hello = { attrs, body ->
out << "Hello ${attrs.name ?: 'World'}"
}
}
并且您有以下控制器:
package org.grails.samples
class SimpleController {
def flashHello() {
flash.message = g.hello()
}
}
您可以使用以下规格进行测试:
package org.grails.samples
import grails.test.mixin.Mock
import grails.test.mixin.TestFor
import spock.lang.Specification
@TestFor(SimpleController)
@Mock(SimpleTagLib)
class SimpleControllerSpec extends Specification {
void 'test flashHello'() {
when:
controller.flashHello()
then:
flash.message == 'Hello World'
}
}
如果您有多个 class 要模拟,您可以在 @Mock
的数组参数中指定它们。因此,您可以通过将 @Mock(User)
更改为 @Mock([User, FormTagLib, YourFixRedisIssueTagLib])
之类的内容,将任何必要的标签库添加到 UserControllerSpec
。但是,如果您确实需要添加 FormTagLib
,我会感到惊讶,因为在我的 Grails 测试中它似乎默认包含。
作为进一步的建议,您发布的某些代码没有任何意义。具体来说:
assertEquals model.pageTitle == 'user.devices', controller.flash.message
具体确定要测试的内容,并专注于为此编写尽可能简单的代码。
此外,根据您对所发生情况的描述,我认为您被抛弃了,因为您的 IDE 没有与 Grails 正确集成以查看 g
上下文。
如标题所述,是否可以对控制器进行单元测试并模拟标签库?
就目前而言,我有一个用户控制器。许多动作使用
g.message(code: 'something.something')
调用以在页面上设置消息。
@TestFor(UserController)
@Mock(User)
@TestMixin(GroovyPageUnitTestMixin)
class UserControllerSpec extends Specification
{
UserService userServiceMock = Mock(UserService)
def setup()
{
controller.userService = userServiceMock
}
def cleanup()
{
}
void "test manageDevice"()
{
given:
def g = mockTagLib(FormTagLib)
when:
controller.manageDevice()
then:
model.pageTitle == 'message.device'
}
使用该代码,我试图点击控制器操作,但由于 g.message,它失败了,并显示一条错误消息,指出它无法将值设置为 null。几乎是因为它没有看到 "g.message"
我有点不确定我的单元测试是否需要以不同的方式编写,或者我是否只是遗漏了一些东西。
任何帮助都会很棒!
编辑:
使用 messageSource 的一些更新:
void "test manageDevice"()
{
given:
messageSource.addMessage 'user.devices', request.locale, 'Manage Devices'
when:
controller.manageDevices()
then:
assertEquals model.pageTitle == 'user.devices', controller.flash.message
}
它似乎还在抱怨,因为它在控制器上没有 "g" 命名空间的上下文。我还要注意,我没有来自 messageSource 的 'addMessage' 上下文。不知道为什么,它应该在那里。
在同一个控制器和许多其他控制器中,我们在控制器范围内使用的唯一标签库是 'g' 用于每个操作中的 'g.message' 集。唯一正在进行的其他调用是使用 'g' 进行调用,例如 'g.fixRedisIssue'
为什么不return消息代码而不是return将消息文本从控制器发送到视图?例如,如果您的视图中有这样的内容:
<p>${flash.message}</p>
您可以将其替换为:
<p><g:message code="${flash.code}" /></p>
然后在控制器中设置代码:
flash.code = "user.devices"
然后您将能够轻松地测试控制器方法:)
您可以通过在规范 class 上的 grails.test.mixin.Mock
注释的值中包含必要的 TagLib classes 来使用模拟的 TagLib 对控制器进行单元测试。例如,如果您有以下 TagLib:
(基于 Grails documentation 中的代码)
package org.grails.samples
class SimpleTagLib {
static namespace = 'g'
def hello = { attrs, body ->
out << "Hello ${attrs.name ?: 'World'}"
}
}
并且您有以下控制器:
package org.grails.samples
class SimpleController {
def flashHello() {
flash.message = g.hello()
}
}
您可以使用以下规格进行测试:
package org.grails.samples
import grails.test.mixin.Mock
import grails.test.mixin.TestFor
import spock.lang.Specification
@TestFor(SimpleController)
@Mock(SimpleTagLib)
class SimpleControllerSpec extends Specification {
void 'test flashHello'() {
when:
controller.flashHello()
then:
flash.message == 'Hello World'
}
}
如果您有多个 class 要模拟,您可以在 @Mock
的数组参数中指定它们。因此,您可以通过将 @Mock(User)
更改为 @Mock([User, FormTagLib, YourFixRedisIssueTagLib])
之类的内容,将任何必要的标签库添加到 UserControllerSpec
。但是,如果您确实需要添加 FormTagLib
,我会感到惊讶,因为在我的 Grails 测试中它似乎默认包含。
作为进一步的建议,您发布的某些代码没有任何意义。具体来说:
assertEquals model.pageTitle == 'user.devices', controller.flash.message
具体确定要测试的内容,并专注于为此编写尽可能简单的代码。
此外,根据您对所发生情况的描述,我认为您被抛弃了,因为您的 IDE 没有与 Grails 正确集成以查看 g
上下文。