【问题标题】:Odd behavior with default index action when unit testing a RestfulController in grails在 grails 中对 RestfulController 进行单元测试时,默认索引操作的奇怪行为
【发布时间】:2015-09-17 06:07:49
【问题描述】:

使用 grails 2.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-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 书籍列表。

&lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;list /&gt;

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

通过将该方法复制到 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 的 index 方法工作而无需将 index 方法复制到 BookController 中,我还需要添加什么到 Spec 中吗?

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

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

【问题讨论】:

    标签: unit-testing grails-2.4


    【解决方案1】:

    使用 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 单元测试免费获得很多魔法,但是当魔法不起作用时,最好尝试不同的测试阶段。

    【讨论】:

      猜你喜欢
      • 2014-07-19
      • 1970-01-01
      • 2015-02-03
      • 2013-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多