在 grails 中对 RestfulController 进行单元测试时,默认索引操作的奇怪行为 [英] Odd behavior with default index action when unit testing a RestfulController in grails

查看:25
本文介绍了在 grails 中对 RestfulController 进行单元测试时,默认索引操作的奇怪行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用 grails 2.4.4(和 2.4.5)我创建了以下小应用程序.

Using grails 2.4.4 (and 2.4.5) I created the following tiny application.

grails create-app example
cd example
grails create-domain-class Book

然后将 Book.groovy 编辑成这样

Then edited Book.groovy to look like

package example
class Book {
    String title;
    static constraints = {
    }
}  

然后添加一个基本的控制器

Then added a basic Controller

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.

and modify the controller to extend RestfulController.

package example
import grails.rest.*
class BookController extends RestfulController<Book> {
    static responseFormats=['json','xml']
    BookController() {
        super(Book)
    }
}

连接 UrlMappings 以将书籍作为/api/books 中的资源提供.

Hook up the UrlMappings to serve up the books as a resource at /api/books.

class UrlMappings {
  static mappings = {
    "/api/books"(resources: "book")
    "/"(view:"/index")
    "500"(view:'/error')
  }
}

最后但并非最不重要的一点是,在 BootStrap.groovy 中构建了几本书.

and last but not least, built a few books in 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.

And everything looks good. The example.Book controller shows up in the index page. The three books can be viewed as json or xml.

现在开始单元测试.

将 BookControllerSpec 编辑为如下所示

Edit the BookControllerSpec to look like this

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 书籍列表.

The first test passes, and the 2nd one fails. The output from the println in the failing test is an empty xml list of books.

<?xml version="1.0" encoding="UTF-8"?><list/>

在调查发生了什么时,我查看了父类(RestfulController)的 index 方法.

While investigating what was going on I looked at the index method of the parent class (RestfulController).

通过将该方法复制到 BookController 中,单元测试将开始通过.

By copying that method into BookController, the unit test will start passing.

-- 带有复制索引方法的 BookController 新版本 --

-- new version of BookController with copied index method --

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 的 index 方法工作而无需将 index 方法复制到 BookController 中,我还需要向 Spec 添加任何其他内容吗?

So is there anything else I need to add to the Spec in order to get the index method of the RestfulController to work without having to copy the index method into the BookController?

知道为什么调用 listAllResources 在直接从 BookController 执行时有效,但从 RestfulController 执行时不返回任何行.

Any idea why the call to listAllResources works when executed directly from BookController, but returns no rows when executed from the RestfulController.

上面的单元测试是 Grails In Action 一书中描述的其余单元测试的修改版本,该书是为 grails 2.3 编写的.http://www.manning.com/gsmith2/

The unit test above is a modified version of the rest unit tests described in the Grails In Action book, which is written for grails 2.3. http://www.manning.com/gsmith2/

推荐答案

单元测试在使用 grails 时会变得非常棘手.我从来没有确定到底是什么导致了这次失败,但我确实发现了另一个奇怪的地方.

Unit tests can get really tricky with grails. I never determined exactly what causes this failure, but I did discover another oddity.

将失败的测试插入规范文件两次将导致它第一次失败,但第二次通过.

Inserting the failing test into the spec file twice will cause it to fail the first time, but pass the 2nd time.

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 测试框架内部的某些东西在第一次调用时未能成功连接该索引方法.

Something deep in the bowels of the grails testing framework doesn't successfully hook up that index method the first time it is called.

我没有进一步挖掘,而是将其重写为集成测试,它开始正常运行.

Instead of digging any further, I just rewrote this as an integration test and it started behaving properly.

您可以通过 grails 单元测试免费获得很多魔力,但是当魔力不起作用时,尝试不同的测试阶段可能会更好.

There is a lot of magic you get for free with grails unit testing, but when the magic doesn't work it's probably better to try a different testing phase.

这篇关于在 grails 中对 RestfulController 进行单元测试时,默认索引操作的奇怪行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆