使用 Spock 进行 Grails 测试 - 选择哪个模拟框架?
Posted
技术标签:
【中文标题】使用 Spock 进行 Grails 测试 - 选择哪个模拟框架?【英文标题】:Grails Testing with Spock - Which Mocking Framework Select? 【发布时间】:2013-07-23 15:30:30 【问题描述】:我有更一般的问题。在使用 Spock 时,我应该使用哪个框架或实现在 Grails 2.x 中进行模拟?
我知道大量的模拟风格:利用 Groovy 元类、Grails mockFor()、Groovy Mock()、Groovy 闭包风格等。它们各有优缺点。但我不明白的是,某些模拟风格在我无法确定的某些情况下有效(即 mockFor() 适用于某些实现而不适用于其他实现)。
目前我有两个类似的服务方法模拟实现。
这个有效:
@TestFor(MyController)
@Mock([MyDevice])
class MyControllerSpec extends ControllerSpec
void "test st."()
def myService = mockFor(MyService)
myService.demand.myMethod() def st ->
return "test"
controller.myService = myService.createMock()
但是,这个实现不起作用:
@TestFor(MyController)
@Mock([MyDevice])
class MyControllerSpec extends ControllerSpec
void "test st."()
def yourService = mockFor(YourService)
yourService.demand.yourMethod() def st ->
return "test"
controller.yourService = yourService.createMock()
服务实现和从控制器调用非常相似。那么在 Grails 中模拟的最佳实践是什么?或者有没有什么好的 Grails 模拟框架可以节省我弄清楚如何模拟的时间?
感谢您的建议! :-)
马特奥
【问题讨论】:
你试过Spock的模拟框架了吗?这真的很简单明了。 spock 文档说它可以与 spock 模拟或 Groovy 模拟一起使用,但警告不要出于某种原因尝试组合这两个模拟框架。 是的,这实际上是你调用 mockFor(); 时将要使用的内容; grails.plugin.spock.UnitSpec.mockFor() 被调用。我发现最有用的是直接使用元类编程来模拟和常规闭包。唯一的问题是,当您不在威胁下降部分清理它时,metaClass 可能会干扰其他测试。也许 Grails 2.3 会带来更好的支持,因为 Spock 将是此版本的默认设置... 如果答案合适并符合您的期望,请接受它以帮助其他人从您的问题中学习。 【参考方案1】:当您使用 spock 框架进行测试时,请尝试利用框架本身提供的选项和样式。
Spock 框架有助于实现 BDD [行为设计开发]。我的意思是行为,您可以将业务接受场景与开发周期紧密结合。
我尝试用 Spock 编写您的测试用例,因为它可以重写为:
@TestFor(MyController)
class MyControllerSpec extends ControllerSpec
void "test service method in called once and only once"()
//Defines the behavior of setup
setup: "Only one invocation of service method"
def myService = Mock(MyService)
//Make sure serviceMethod is called only once from the controller
//Beauty of Spock is that you can test the cardinality of
//method invocations.
1 * serviceMethod() >> "Hello"
controller.myService = myService
//The above process can be followed
//for stubbing/mocking 'YourService' and
//then injecting it to controller like
//controller.yourService = yourService
//Defines the behavior of action
when: "controller action is called"
controller.myAction()
//Defines the behavior of expected results
then: "Expect the stubbed service method output"
controller.response.contentAsString == "Hello"
//Controller
def myAction()
render myService.serviceMethod()
如果您在上面看到,您定义了每个步骤中的行为。从企业的角度来看,这些行为将由 BA 或利益相关者驱动。通过这种方式,您可以遵守 ATDD/BDD(Acceptance Test Driven Dev/Behavior Test Driven Dev),并最终为您的项目遵守 TDD(Test Driven Dev)。
有关如何有效使用 spock 框架的更多详细信息,请访问 spock 框架docs。
【讨论】:
以上是关于使用 Spock 进行 Grails 测试 - 选择哪个模拟框架?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Grails 单元测试中使用 Spock 模拟 passwordEncoder
IntelliJ IDEA 的零覆盖:带有 Spock 单元测试的 Grails
如何在 Spock 控制器测试中模拟 Grails 请求对象方法
在 Intellij Idea 中运行 grails 2.1.3 测试:Spock 测试中出现奇怪错误:无法添加域类 [class x.y.Z]。它不是域