Jojje
Jojje

Reputation: 1779

How to populate domain classes in Grails 3 for unit tests

I was wondering as to how to build up a world of Domain class objects to use in my unit tests. What´s the best approach?

Say this is my code, ServiceX:

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

This is the test for 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
     }

}

How can I "pre populate" the test-db (memory) sow that I actually have 4 such objects in the list?

Upvotes: 0

Views: 1600

Answers (3)

Jojje
Jojje

Reputation: 1779

It turns out you can add / override methods to the domain classes (for example), something like this:

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
 }

}

Upvotes: 0

Mike Houston
Mike Houston

Reputation: 264

This is a judgement call for when to test using a slow integration test. The key is to test your code, not the Grails/hibernate DB code.

Integration tests should not be needed for the bulk of the service testing. I do think you need an integration test for the object interactions in a running system with a real DB. I tend to do that in GUI tests using GEB. These tests usually cover basic end-to-end scenarios. That tests the server side and the GUI interaction with the server.

In the GUI/GEB tests, I don't test all permutations and edge conditions of the service. I do most of that edge testing in unit tests.

I have found that with Grails, if one simple DB action works in an integration test, then most other simple DB actions work. The Grails domain mocks for save(), delete(), etc simulate the 'real' DB actions fairly well. Note: they do operate on objects in memory, so it is not exactly the same.

I don't use Spock, but with JUnit I use this approach (still works with Grails 3):

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

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

This appears to be supported with Spock. I would assume this creation of domain records belongs in the Spock 'given' section. Also, see Grails Testing.

Another great resource is to search the Grails source on Github. I learned a lot from their examples.

Upvotes: 0

Piotr Chowaniec
Piotr Chowaniec

Reputation: 1230

Create integration test for this. See an example here.

Upvotes: 1

Related Questions