我想为用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')
}
}
答案 0 :(得分:1)
免责声明:我对Grails框架没有任何经验,但是曾经使用过Spock。
根据您的问题:
您说:控制器是一个真实的对象,因此应在测试中使用如下代码创建它:
controller = new SomeController(<dependencies>)
但是随后您指定了对真实对象的期望-IMO不能这样工作,您可以仅对在其实现中具有该功能的代理(存根,模拟,间谍)指定期望,真实对象显然没有
所以基本上,您有两种方法:
选项1:间谍控制器
Controller本身必须是Spy:这是包装真实对象(真实控制器)的东西,默认情况下,将所有方法调用委托给该内部真实对象,除非您不“抑制”此功能(在本示例中情况下,您说类似:行为像真实对象,但是如果有人调用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)
...
}