PJT
PJT

Reputation: 3597

Writing an Integration Test in Grails that will test DB persistence

My Integration-Test for my grails application is returning a null object when I try to get a domain object using grails dynamic get method. This is a simplified example of my problem. Lets say I have a controller TrackerLogController that uses a service TrackerLogService to save an updated Log domain for another Tracker domain. Domain Tracker:

class Tracker {

   int id
   String name

   static hasMany = [logs: Log] 
}

Domain Log:

class Log {
   int id
   String comment

   static belongsTo = [tracker: Tracker]
}

Controller TrackerLogController save:

def TrackerLogService

def saveTrackerLog() {

   def trackerId = params.trackerId

   def trackerInstance = Tracker.get(trackerId)
   Log log = TrackerLogService.saveTrackerLogs(trackerInstance, params.comment)
   if( log.hasErrors() ){
      //render error page
   }
   //render good page
}

Service TrackerLogService save:

Log saveTrackerLogs( Tracker tracker, String comment) {
   Log log = new Log(tracker: tracker, comment: comment)
   log.save()
   return log
}

So now I want to write an Integration-Test for this service but I'm not sure if I should be writing one just for the simple logic in the controller (if error, error page else good page) I would think I would write a Unit test for that, and an Integration-Test to check the persistence in the Database.

This is what I have for my Integration-Test:

class TrackerLogServiceTests {

   def trackerLogService

   @Before
   void setUp(){

      def tracker = new Tracker(id: 123, name: "First")

      tracker.save()

      //Now even if I call Tracker.get(123) it will return a null value...
   }

   @Test
   void testTrackerLogService() {
      Tacker trackerInstance  = Tracker.get(123) //I have tried findById as well 

      String commit = "This is a commit" 

      //call the service
      Log log = trackerLogService.saveTrackerLogs(trackerInstance , commit)

      //want to make sure I added the log to the tracker Instance
      assertEquals log , trackerInstance.logs.findByCommit(commit)
   }
}

So for this example my trackerInstance would be a null object. I know the Grails magic doesn't seem to work for Unit tests without Mocking, I thought for Intigration-Tests for persistence in the DB you would be able to use that grails magic.

Upvotes: 0

Views: 4694

Answers (1)

Burt Beckwith
Burt Beckwith

Reputation: 75681

You can't specify the id value unless you declare that it's "assigned". As it is now it's using an auto-increment, so your 123 value isn't used. It's actually ignored by the map constructor for security reasons, so you'd need to do this:

def tracker = new Tracker(name: "First")
tracker.id = 123

but then it would get overwritten by the auto-increment lookup. Use this approach instead:

class TrackerLogServiceTests {

   def trackerLogService

   private trackerId

   @Before
   void setUp(){    
      def tracker = new Tracker(name: "First")
      tracker.save()
      trackerId = tracker.id
   }

   @Test
   void testTrackerLogService() {
      Tacker trackerInstance  = Tracker.get(trackerId)

      String commit = "This is a commit" 

      //call the service
      Log log = trackerLogService.saveTrackerLogs(trackerInstance , commit)

      //want to make sure I added the log to the tracker Instance
      assertEquals log , trackerInstance.logs.findByCommit(commit)
   }
}

Also, unrelated - don't declare the id field unless it's a nonstandard type, e.g. a String. Grails adds that for you, along with the version field. All you need is

class Tracker {
   String name
   static hasMany = [logs: Log] 
}

and

class Log {
   String comment
   static belongsTo = [tracker: Tracker]
}

Upvotes: 3

Related Questions