Unit testing 如何在动态搭建的Grails控制器的集成测试中模拟服务?
我试图在一个动态搭建的控制器的集成测试中模拟一个服务。我收到一个错误,指示无法从测试访问服务的控制器属性 看起来动态搭建的控制器根本无法通过单元测试进行测试,所以我使用的是集成测试。我想模拟服务来测试我的应用程序中的错误处理。这是Grails2.2.0中的一个bug还是我只是做错了 grails测试应用程序的结果是:Unit testing 如何在动态搭建的Grails控制器的集成测试中模拟服务?,unit-testing,grails,mocking,Unit Testing,Grails,Mocking,我试图在一个动态搭建的控制器的集成测试中模拟一个服务。我收到一个错误,指示无法从测试访问服务的控制器属性 看起来动态搭建的控制器根本无法通过单元测试进行测试,所以我使用的是集成测试。我想模拟服务来测试我的应用程序中的错误处理。这是Grails2.2.0中的一个bug还是我只是做错了 grails测试应用程序的结果是: groovy.lang.MissingPropertyException: No such property: myService for class: MyController
groovy.lang.MissingPropertyException: No such property: myService for class: MyController
例如:
我已经修改了src/templates/scaffolding/Controller.groovy
:
class ${className}Controller {
MyService myService
def action() {
render myService.serviceMethod()
}
}
class MyController {
static scaffold = MyDomainClass
}
class MyControllerTests extends GroovyTestCase {
def myController
@Before
void setUp() {
myController = new MyController()
}
void testMock() {
myController.myService = [ serviceMethod : { return "foo" } ] as MyService
controller.action()
}
}
动态搭建MyController.groovy
:
class ${className}Controller {
MyService myService
def action() {
render myService.serviceMethod()
}
}
class MyController {
static scaffold = MyDomainClass
}
class MyControllerTests extends GroovyTestCase {
def myController
@Before
void setUp() {
myController = new MyController()
}
void testMock() {
myController.myService = [ serviceMethod : { return "foo" } ] as MyService
controller.action()
}
}
集成测试MyControllerTests.groovy
:
class ${className}Controller {
MyService myService
def action() {
render myService.serviceMethod()
}
}
class MyController {
static scaffold = MyDomainClass
}
class MyControllerTests extends GroovyTestCase {
def myController
@Before
void setUp() {
myController = new MyController()
}
void testMock() {
myController.myService = [ serviceMethod : { return "foo" } ] as MyService
controller.action()
}
}
尝试使用setter方法:
void testMock() {
myController.setMyService([ serviceMethod : { return "foo" } ])
controller.action()
}
如果执行:
println c.metaClass.methods*.name
,您将看到有像getSetMyService()和getGetMyService()这样的方法。我不确定,但Grails可能不是在添加字段,而是在为字段get/set方法添加getter。集成测试应该如下所示实现。如果我们在测试中模拟服务,我们必须自己重置它。Grails并没有为我们做这件事,这很神秘,因为控制器是在setUp()
中创建的
上面droggo的回答揭示了在SUT中注入模拟的正确方法。我还将添加一个使用Groovy模拟的示例。不过有点冗长
class MyControllerTests extends GroovyTestCase {
def myController
def myService
@Before
void setUp() {
myController = new MyController()
}
@After
void tearDown() {
myController.setMyService(myService)
}
void testMapMock() {
myController.setMyService([ serviceMethod : { return "foo" } ] as MyService)
controller.action()
}
void testGroovyMock() {
def myServiceMockContext = new StubFor(MyService)
myServiceMockContext.demand.serviceMethod() { -> return "bar" }
def myService = myServiceMockContext.proxyInstance()
controller.setMyService(myService)
controller.action()
}
}
谢谢setXxxService()方法成功了!作为参数的映射需要类型转换:
controller.setMyService([…]作为MyService)
。此外,您需要在下一次测试中将服务重置为真实服务。Grails似乎在mock设置完成后仍保留着它。我将在下面的另一个答案中展示一个示例实现。