如何在 Grails 3 中填充域 类 以进行单元测试

How to populate domain classes in Grails 3 for unit tests

我想知道如何构建域 class 对象的世界以在我的单元测试中使用。什么是最好的方法?

说这是我的代码,ServiceX:

   List<Course> getAllCoursesByType(String type) {
        List<Course> list = Course.findAllByType(type)
        list
   }

这是对 ServiceX 的测试:

 import grails.buildtestdata.mixin.Build
 import grails.test.mixin.TestFor
 import grails.test.mixin.Mock
 import spock.lang.Specification


  @TestFor(ServiceX)

    class ServiceXSpec extends Specification { 

      void "get all open courses"() {
       given:
       String type = "open"
       when:
       def list = service.getAllCoursesByType(type)

       then:
      list.size() == 4
     }

}

我怎样才能 "pre populate" test-db(内存)表明我实际上在列表中有 4 个这样的对象?

为此创建集成测试。请参阅示例 here

这是对何时使用慢速集成测试进行测试的判断要求。关键是测试您的代码,而不是 Grails/hibernate 数据库代码。

大部分服务测试不需要集成测试。我确实认为您需要对具有真实数据库的 运行 系统中的对象交互进行集成测试。我倾向于在使用 GEB 的 GUI 测试中这样做。这些测试通常涵盖基本的端到端场景。这将测试服务器端以及与服务器的 GUI 交互。

在 GUI/GEB 测试中,我没有测试服务的所有排列和边缘条件。我在单元测试中进行了大部分边缘测试。

我发现,对于 Grails,如果一个简单的数据库操作在集成测试中有效,那么大多数其他简单的数据库操作都有效。用于 save()、delete() 等的 Grails 域模拟相当好地模拟了 'real' 数据库操作。 注意:它们都是对内存中的对象进行操作,所以并不完全相同。

我不使用 Spock,但是对于 JUnit,我使用这种方法(仍然适用于 Grails 3):

@TestFor(ServiceX)
@Mock([Course])
class ServiceXTests {
}

@Test
void testXYZ() {
  def course= new Course(course: 'ABC')
  assert course.save()
  . . . 
}

Spock 似乎支持此功能。我假设这个域记录的创建属于 Spock 'given' 部分。另请参阅 Grails Testing

另一个很好的资源是在 Github 上搜索 Grails 源代码。我从他们的例子中学到了很多。

事实证明,您可以向域 类 添加/覆盖方法(例如),如下所示:

import grails.buildtestdata.mixin.Build
import grails.test.mixin.TestFor
import grails.test.mixin.Mock
import spock.lang.Specification
import grails.test.mixin.Mock


@Mock([Course])
@TestFor(ServiceX)

class ServiceXSpec extends Specification { 

  void "get all open courses"() {
   given:
   String type = "open"

   Course.metaclass.static.findAllByType = { String type -> [new Course()]}
   when:
   def list = service.getAllCoursesByType(type)

   then:
   list.size() == 1
 }

}