Unit testing 在grails中对RestfulController进行单元测试时,使用默认索引操作的奇怪行为
我使用Grails2.4.4(和2.4.5)创建了以下微型应用程序Unit testing 在grails中对RestfulController进行单元测试时,使用默认索引操作的奇怪行为,unit-testing,grails-2.4,Unit Testing,Grails 2.4,我使用Grails2.4.4(和2.4.5)创建了以下微型应用程序 grails create-app example cd example grails create-domain-class Book 然后编辑Book.groovy使其看起来像 package example class Book { String title; static constraints = { } } 然后添加了一个基本控制器 grails> create-controll
grails create-app example
cd example
grails create-domain-class Book
然后编辑Book.groovy使其看起来像
package example
class Book {
String title;
static constraints = {
}
}
然后添加了一个基本控制器
grails> create-controller example.book
| Created file grails-app/controllers/example/BookController.groovy
| Created file grails-app/views/book
| Created file test/unit/example/BookControllerSpec.groovy
并修改控制器以扩展RestfulController
package example
import grails.rest.*
class BookController extends RestfulController<Book> {
static responseFormats=['json','xml']
BookController() {
super(Book)
}
}
最后但并非最不重要的是,在BootStrap.groovy中构建了一些书籍
import example.*
class BootStrap {
def init = { servletContext ->
new Book(title: "Book 1").save(failOnError:true);
new Book(title: "Book 2").save(failOnError:true);
new Book(title: "Book 3").save(failOnError:true);
}
def destroy = {
}
}
然后grails运行应用程序
一切看起来都很好。示例.Book控制器显示在索引页中。这三本书可以看作是json或xml
现在来进行单元测试
编辑BookControllerSpec使其如下所示
package example
import grails.test.mixin.TestFor
import grails.test.mixin.Mock
import spock.lang.Specification
@TestFor(BookController)
@Mock(Book)
class BookControllerSpec extends Specification {
def setup() {
new Book(title: "Unit Test Book 1").save(failOnError:true);
new Book(title: "Unit Test Book 2").save(failOnError:true);
new Book(title: "Unit Test Book 3").save(failOnError:true);
}
void "My Setup Worked"() {
given: "My setup ran"
when: "I ask for the count"
then: "I should get back 3"
Book.count() == 3;
}
void "I can access my Controller index method"() {
given: "My setup ran"
when: "I call index"
request.method="GET"
response.format="xml"
controller.index();
then: "I get an XML object back with 3 books"
println response.contentAsString
response.xml.book*.title.size()==3
}
}
第一个测试通过,第二个测试失败。失败测试中println的输出是一个空的xml书籍列表
在调查发生了什么时,我查看了父类(RestfulController)的index方法
通过将该方法复制到BookController中,单元测试将开始通过
--具有复制索引方法的新版BookController--
包示例
导入grails.rest*
类BookController扩展了RestfulController{
静态响应格式=['json','xml']
图书管理员(){
超级(书)
}
def索引(最大整数){
params.max=Math.min(max?:10100)
respond listalresources(params),模型:[(${resourceName}Count.toString()):countResources()]
}
}
那么,为了让RestfulController的index方法能够工作,而不必将index方法复制到BookController中,我还需要向规范中添加其他内容吗
知道为什么直接从BookController执行对listAllResources
的调用有效,但从RestfulController执行时不返回行吗
package example
import grails.rest.*
class BookController extends RestfulController<Book> {
static responseFormats=['json','xml']
BookController() {
super(Book)
}
}
上面的单元测试是Grails in Action手册中描述的rest单元测试的修改版本,该书是为Grails 2.3编写的 使用grails时,单元测试可能会变得非常棘手。我从来没有确定这次失败的确切原因,但我确实发现了另一个奇怪之处 将失败的测试插入spec文件两次将导致它第一次失败,但第二次通过
void "first call to index doesn't work."() {
given: "My setup ran"
when: "I call index"
request.method="GET"
response.format="xml"
controller.index();
then: "I get an XML object back with 3 books"
println response.contentAsString
response.xml.book*.title.size()==3
}
void "2nd call to index works"() {
given: "My setup ran"
when: "I call index"
request.method="GET"
response.format="xml"
controller.index();
then: "I get an XML object back with 3 books"
println response.contentAsString
response.xml.book*.title.size()==3
}
grails测试框架中的某些深层次问题在第一次调用该索引方法时并没有成功地将其连接起来
我没有进一步挖掘,只是将其改写为一个集成测试,它开始正常运行
grails单元测试有很多免费的魔法,但是当魔法不起作用时,最好尝试不同的测试阶段
void "first call to index doesn't work."() {
given: "My setup ran"
when: "I call index"
request.method="GET"
response.format="xml"
controller.index();
then: "I get an XML object back with 3 books"
println response.contentAsString
response.xml.book*.title.size()==3
}
void "2nd call to index works"() {
given: "My setup ran"
when: "I call index"
request.method="GET"
response.format="xml"
controller.index();
then: "I get an XML object back with 3 books"
println response.contentAsString
response.xml.book*.title.size()==3
}