Grails 的正确 Spock 语法是什么?
What is the correct Spock syntax for Grails?
我有一个 Grails 2.5.0 应用程序 运行ning 和这个测试:
package moduleextractor
import grails.test.mixin.TestFor
import spock.lang.Specification
/**
* See the API for {@link grails.test.mixin.web.ControllerUnitTestMixin} for usage instructions
*/
@TestFor(ExtractorController)
class ExtractorControllerSpec extends Specification {
def moduleDataService
def mockFile
def setup() {
moduleDataService = Mock(ModuleDataService)
mockFile = Mock(File)
}
def cleanup() {
}
void "calls the moduleDataService"() {
given: 'a term is passed'
params.termCode = termCode
when: 'the getModuleData action is called'
controller.getModuleData()
then: 'the service is called 1 time'
1 * moduleDataService.getDataFile(termCode, 'json') >> mockFile
where:
termCode = "201415"
}
}
如果我 运行 grails test-app unit:spock
我明白了:
| Tests PASSED - view reports in /home/foo/Projects/moduleExtractor/target/test-reports
我不明白为什么它会看到 2 个测试。我没有在我的 BuildConfig 文件中包含 spock,因为它已经包含在 Grails 2.5.0 中。此外,测试不应该通过,因为我还没有服务。为什么会通过?
另外,当我 运行 这个 grails test-app ExtractorController
我得到另一个结果:
| Running 2 unit tests...
| Running 2 unit tests... 1 of 2
| Failure: calls the moduleDataService(moduleextractor.ExtractorControllerSpec)
| Too few invocations for:
1 * moduleDataService.getDataFile(termCode, 'json') >> mockFile (0 invocations)
Unmatched invocations (ordered by similarity):
None
at org.spockframework.mock.runtime.InteractionScope.verifyInteractions(InteractionScope.java:78)
at org.spockframework.mock.runtime.MockController.leaveScope(MockController.java:76)
at moduleextractor.ExtractorControllerSpec.calls the moduleDataService(ExtractorControllerSpec.groovy:27)
| Completed 1 unit test, 1 failed in 0m 3s
| Tests FAILED - view reports in /home/foo/Projects/moduleExtractor/target/test-reports
| Error Forked Grails VM exited with error
如果我 运行 grails test-app unit:
我得到:
| Running 4 unit tests...
| Running 4 unit tests... 1 of 4
| Failure: calls the moduleDataService(moduleextractor.ExtractorControllerSpec)
| Too few invocations for:
1 * moduleDataService.getDataFile(termCode, 'json') >> mockFile (0 invocations)
Unmatched invocations (ordered by similarity):
None
at org.spockframework.mock.runtime.InteractionScope.verifyInteractions(InteractionScope.java:78)
at org.spockframework.mock.runtime.MockController.leaveScope(MockController.java:76)
at moduleextractor.ExtractorControllerSpec.calls the moduleDataService(ExtractorControllerSpec.groovy:27)
| Completed 1 unit test, 1 failed in 0m 3s
| Tests FAILED - view reports in /home/foo/Projects/moduleExtractor/target/test-reports
| Error Forked Grails VM exited with error
首先有人能告诉我 运行 spock 测试的正确语法是什么吗?
此外,在命令中使用 unit
和 unit:
以及 unit:spock
有什么区别?
(由于 Spock 随 Grails 2.5.0 一起提供,因此无论如何它都会 运行 spocks 测试。)
什么是正确的语法?为什么它看到 2 个测试而不是 1 个?
不要在意测试的数量。这对我来说从来都不是问题。您可以随时检查报告 HTML 文件以确切了解 运行.
我总是运行我的测试
grails test-app
或
grails test-app ExtractorController
您遇到的错误意味着您将测试编码为期望 moduleDataService.getDataFile() 以参数 null 和 'json' 当调用 controller.getModuleData() 时。但是,moduleDataService.getDataFile() 从未被调用,因此测试失败。
Spock 需要一些时间来适应。我建议查看 Grails 文档中的示例并阅读 Spock Framework Reference.
第一个问题:对于 'grails test-app unit:spock',您是否查看了结果以查看其表示通过的测试? CLI 的测试计数可能是错误的,请检查您的结果以查看实际 运行(如果实际上没有测试 运行,则没有失败)。
您的测试方法不是以 'test' 开头,也没有 @Test 注释,因此 'void "calls the moduleDataService"' 不会被视为 spock 测试用例(我相信这是原因)。
当您 运行 'grails test-app ExtractorController' 时,您没有指定它必须是 spock 测试,因此 grails 测试会找到并执行 'calls the moduleDataService' 测试方法。
由于spock是事实上的测试框架,你可以直接使用:
grails test-app -unit
第二个问题:
@TestFor 创建您的控制器,但如果您要 运行 进行单元测试,那么通常的 grails 魔术就不会发生。您的控制器代码是独立执行的。如果您的 ExtractorController 通常注入了 moduleDataService,则您必须注意这一点。
我在 grails 2.4.3 工作,这里是我对你的测试的解释(肯定需要调整,因为我在这个例子中推断了很多):
import grails.test.mixin.TestFor
import grails.test.mixin.Mock
import spock.lang.specification
import some.pkg.ModuleDataService // if necessary
import some.pkg.File // if necessary
@TestFor(ExtractorController)
@Mock([ModuleDataService, File])
class ExtractorControllerSpec extends Specification
def "test callsModuleDataService once for a termCode"() {
setup:
def mockFile = mockFor(File)
def mockService = mockFor(ModuleDataService, true) // loose mock
// in this mockService, we expect getDataFile to be called
// just once, with two parameters, and it'll return a mocked
// file
mockService.demand.getDataFile(1) { String termCode, String fmt ->
return mockFile.createMock()
}
controller.moduleDataService = mockService.createMock()
when:
controller.params.termCode = "201415"
controller.getModuleData()
then:
response.status == 200 // all good?
}
}
最后一个问题:那是Banner字词代码吗? (只是好奇)
我有一个 Grails 2.5.0 应用程序 运行ning 和这个测试:
package moduleextractor
import grails.test.mixin.TestFor
import spock.lang.Specification
/**
* See the API for {@link grails.test.mixin.web.ControllerUnitTestMixin} for usage instructions
*/
@TestFor(ExtractorController)
class ExtractorControllerSpec extends Specification {
def moduleDataService
def mockFile
def setup() {
moduleDataService = Mock(ModuleDataService)
mockFile = Mock(File)
}
def cleanup() {
}
void "calls the moduleDataService"() {
given: 'a term is passed'
params.termCode = termCode
when: 'the getModuleData action is called'
controller.getModuleData()
then: 'the service is called 1 time'
1 * moduleDataService.getDataFile(termCode, 'json') >> mockFile
where:
termCode = "201415"
}
}
如果我 运行 grails test-app unit:spock
我明白了:
| Tests PASSED - view reports in /home/foo/Projects/moduleExtractor/target/test-reports
我不明白为什么它会看到 2 个测试。我没有在我的 BuildConfig 文件中包含 spock,因为它已经包含在 Grails 2.5.0 中。此外,测试不应该通过,因为我还没有服务。为什么会通过?
另外,当我 运行 这个 grails test-app ExtractorController
我得到另一个结果:
| Running 2 unit tests...
| Running 2 unit tests... 1 of 2
| Failure: calls the moduleDataService(moduleextractor.ExtractorControllerSpec)
| Too few invocations for:
1 * moduleDataService.getDataFile(termCode, 'json') >> mockFile (0 invocations)
Unmatched invocations (ordered by similarity):
None
at org.spockframework.mock.runtime.InteractionScope.verifyInteractions(InteractionScope.java:78)
at org.spockframework.mock.runtime.MockController.leaveScope(MockController.java:76)
at moduleextractor.ExtractorControllerSpec.calls the moduleDataService(ExtractorControllerSpec.groovy:27)
| Completed 1 unit test, 1 failed in 0m 3s
| Tests FAILED - view reports in /home/foo/Projects/moduleExtractor/target/test-reports
| Error Forked Grails VM exited with error
如果我 运行 grails test-app unit:
我得到:
| Running 4 unit tests...
| Running 4 unit tests... 1 of 4
| Failure: calls the moduleDataService(moduleextractor.ExtractorControllerSpec)
| Too few invocations for:
1 * moduleDataService.getDataFile(termCode, 'json') >> mockFile (0 invocations)
Unmatched invocations (ordered by similarity):
None
at org.spockframework.mock.runtime.InteractionScope.verifyInteractions(InteractionScope.java:78)
at org.spockframework.mock.runtime.MockController.leaveScope(MockController.java:76)
at moduleextractor.ExtractorControllerSpec.calls the moduleDataService(ExtractorControllerSpec.groovy:27)
| Completed 1 unit test, 1 failed in 0m 3s
| Tests FAILED - view reports in /home/foo/Projects/moduleExtractor/target/test-reports
| Error Forked Grails VM exited with error
首先有人能告诉我 运行 spock 测试的正确语法是什么吗?
此外,在命令中使用 unit
和 unit:
以及 unit:spock
有什么区别?
(由于 Spock 随 Grails 2.5.0 一起提供,因此无论如何它都会 运行 spocks 测试。)
什么是正确的语法?为什么它看到 2 个测试而不是 1 个?
不要在意测试的数量。这对我来说从来都不是问题。您可以随时检查报告 HTML 文件以确切了解 运行.
我总是运行我的测试
grails test-app
或
grails test-app ExtractorController
您遇到的错误意味着您将测试编码为期望 moduleDataService.getDataFile() 以参数 null 和 'json' 当调用 controller.getModuleData() 时。但是,moduleDataService.getDataFile() 从未被调用,因此测试失败。
Spock 需要一些时间来适应。我建议查看 Grails 文档中的示例并阅读 Spock Framework Reference.
第一个问题:对于 'grails test-app unit:spock',您是否查看了结果以查看其表示通过的测试? CLI 的测试计数可能是错误的,请检查您的结果以查看实际 运行(如果实际上没有测试 运行,则没有失败)。
您的测试方法不是以 'test' 开头,也没有 @Test 注释,因此 'void "calls the moduleDataService"' 不会被视为 spock 测试用例(我相信这是原因)。
当您 运行 'grails test-app ExtractorController' 时,您没有指定它必须是 spock 测试,因此 grails 测试会找到并执行 'calls the moduleDataService' 测试方法。
由于spock是事实上的测试框架,你可以直接使用: grails test-app -unit
第二个问题:
@TestFor 创建您的控制器,但如果您要 运行 进行单元测试,那么通常的 grails 魔术就不会发生。您的控制器代码是独立执行的。如果您的 ExtractorController 通常注入了 moduleDataService,则您必须注意这一点。
我在 grails 2.4.3 工作,这里是我对你的测试的解释(肯定需要调整,因为我在这个例子中推断了很多):
import grails.test.mixin.TestFor
import grails.test.mixin.Mock
import spock.lang.specification
import some.pkg.ModuleDataService // if necessary
import some.pkg.File // if necessary
@TestFor(ExtractorController)
@Mock([ModuleDataService, File])
class ExtractorControllerSpec extends Specification
def "test callsModuleDataService once for a termCode"() {
setup:
def mockFile = mockFor(File)
def mockService = mockFor(ModuleDataService, true) // loose mock
// in this mockService, we expect getDataFile to be called
// just once, with two parameters, and it'll return a mocked
// file
mockService.demand.getDataFile(1) { String termCode, String fmt ->
return mockFile.createMock()
}
controller.moduleDataService = mockService.createMock()
when:
controller.params.termCode = "201415"
controller.getModuleData()
then:
response.status == 200 // all good?
}
}
最后一个问题:那是Banner字词代码吗? (只是好奇)