使用grails 2.4.4(和2.4.5)我创建了下面的小应用程序。单元测试grails中的RestfulController时使用默认索引操作的奇怪行为
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)
}
}
挂钩UrlMappings将图书作为资源提供给/ api/books。
class UrlMappings {
static mappings = {
"/api/books"(resources: "book")
"/"(view:"/index")
"500"(view:'/error')
}
}
最后但并非最不重要的是,在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 run-app
,一切看起来不错。 example.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书籍列表。
<?xml version="1.0" encoding="UTF-8"?><list />
在调查发生了什么事情我看着父类(RestfulController)的索引方法。
通过将该方法复制到BookController中,单元测试将开始传递。
- BookController的新版本复制指数的方法 -
package example
import grails.rest.*
class BookController extends RestfulController<Book> {
static responseFormats=['json','xml']
BookController() {
super(Book)
}
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
respond listAllResources(params), model: [("${resourceName}Count".toString()): countResources()]
}
}
那么,还有什么需要补充的规格,以获得RestfulController的索引方法,而无需工作将索引方法复制到BookController中?
任何想法为什么直接从BookController执行时调用listAllResources
的原因,但从RestfulController执行时不返回任何行。
上面的单元测试是为grails 2.3编写的Grails In Action书中描述的其余单元测试的修改版本。 http://www.manning.com/gsmith2/