Search code examples
grailsgroovyspockgeb

How do you get the sessionFactory in a Grails Geb/Spock test case?


I think I need to flush the hibernate session in a GebSpec test, and so I want to get the sessionFactory.

It looks like it should be injected but when I do something like this:-

class MySpec extends GebSpec {
def sessionFactory
...
def "test session"(){
....do some setup
then: 
  assert sessionFactory != null
}

it fails with sessionFactory being null.


Solution

  • The short answer to my question is - why do you want to do that, it's a functional test and it may be remote from the running apps JVM.

    The why is because I want to check that domain objects have been updated when web stuff happens. Luke Daley kindly pointed out that you can do that using the Remote-Control Grails plug in ( https://github.com/alkemist/grails-remote-control ) which is pretty cool. You install the plugin then go

     assert remote {
      MyDomainOb.findByName('fred') != null
     }
    

    And it sends that closure to be executed on the server and returns the result, which you can test. The result must be serialisable.

    OK so that's one way - but the remote plugin is a little harder to get results back for tests if you have a lot of intricate objects changing under the hood due to a domain model that is imposed on you. So how do you get the tests hibernate session when you are on the same JVM?? Like this:-

    Session currentSession
    
        def setup() {
            ApplicationContext context = (ApplicationContext) ServletContextHolder.getServletContext().getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT);
            SessionFactory sf = context.getBean('sessionFactory')
            currentSession = sf.getCurrentSession()
        }
    

    Add that to the top of your GebSpec and then you can call currentSession.clear() or currentSession.flush()

    I needed to have the tests session update so currentsession.clear() was the answer.

    Note this won't help you if the target under test is in a separate VM, so you'll have to use remote.