grails - 使用 Spock 模拟真实对象的功能
问题描述
我想为使用 Grails 框架编写的 Web 应用程序添加一些控制器单元测试。
我需要跳过控制器getMessage()
中方法中使用的cancel_request()
方法作为真实对象。
class PublicControllerSpec extends Specification implements ControllerUnitTest<PublicController> {
def "Cancel Request for user"() {
given:
controller.getMessage() << Spy(PublicController){
getMessage(_ as User, _ as String) >> "SuccessMessage"
}
when:
controller.cancel_request()
then:
response.redirectedUrl.contains('/public/list')
}
}
解决方案
免责声明:我对 Grails 框架没有任何经验,但曾经使用过 Spock
根据您的问题:
你说:控制器是一个真实的对象,所以它应该在测试中用这样的代码创建:
controller = new SomeController(<dependencies>)
但是然后您指定对真实对象的期望 - IMO 它不会像这样工作,您可以仅在代理(存根、模拟、间谍)上指定期望,它们在实现中具有该功能,而真实对象显然没有。
所以基本上你有两种方法:
选项 1:监视控制器
控制器本身必须是一个间谍:这是包装真实对象(真实控制器)的东西,默认情况下将所有方法调用委托给该内部真实对象,除非您不“抑制”此功能(在这种情况下,您说这样的话:表现得像一个真实的对象,但如果有人打电话getMessage
,那么返回一条消息而不是委托给真实的对象)。这种方式的明显缺点是被测对象(控制器)变成了间谍,这不是一个好方法。
选项 2:重构代码
我承认,由于我没有使用 Grails 的经验,我可能会在这里遗漏一些东西,但如果控制器是您编写的代码,您可能会选择以下更改:
引入一个依赖:一个负责消息计算的类,例如:
interface MessageCalculator {
String getMessage()
}
class MyController {
MessageCalculator messageCalculator
MyController(MessageCalculator messageCalculator) {
this.messageCalculator = messageCalculator
}
public getMessage() {
messageCalculator.getMessage()
}
}
旁注:是的,我知道这里可以应用 AST 转换,但这不是问题的主题,所以我会留下这样的代码
无论如何,现在您可以按如下方式重新实现测试:
def "test me now"() {
given:
def msgCalc = Stub(MessageCalculator)
msgCalc.getMessage() >> "Successfull message"
def controller = new MyController(msgCalc)
...
}
推荐阅读
- python - NoSuchModuleError:无法加载插件:sqlalchemy.dialects:teradata
- ios - iOS图表框架maximumFractionDigits不起作用
- r - 从多个线性模型中获取斜率、截距和确定系数,所有这些都来自同一个数据帧
- javascript - Javascript 按钮按条件显示
- visual-studio-code - vscode 在 Windows 7 上没有为我启动
- c++ - 为什么我不能自己移动构造一个 unique_ptr ?
- java - Java 8 - Quartz Scheduler 每天在特定时间安排任务
- mysql - 没有从相关表中删除记录 - ON DELETE CASCADE 不起作用
- windows - 在 Windows [脚本] 中将子文件夹上移一级
- google-play - 应用内结算 - 当 queryPurchases() 返回一个空列表时,Google Play 给我“您已经拥有此商品”消息