0

Have a @PostConstruct in the service to ensure that the dependencies have been set up. Dependencies are set in resources.groovy. Unit test fails on @PostConstruct asserts. Tried setting up the dependencies manually in setUpSpec to no avail. Even without a @TestFor, ServiceUnitTestMixin kicks in and merrily chokes on @PostConstruct. Opened a defect GRAILS-11878 which was closed promptly with an advice to use @FreshRuntime and doWithSpring. If they actually bothered to try, they'd have gotten the following error:

org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'grails.spring.BeanBuilder$ConfigurableRuntimeBeanReference$WrappedPropertyValue@2cce10bc' with class 'grails.spring.BeanBuilder$ConfigurableRuntimeBeanReference$WrappedPropertyValue' to class 'java.util.Collection' 

Service under test:

@Transactional
class MovieRipIndexService {

    Collection<String> genres

    Collection<String> includes

    @PostConstruct
    void postConstruct() {
        notEmpty(genres as Collection, 'Genres must not be null or empty.')
        notEmpty(includes as Collection, 'Includes must not be null or empty.')
    }
}

Test:

@FreshRuntime
@TestFor(MovieRipIndexService)
class MovieRipIndexServiceSpec extends Specification {

    def doWithSpring = {
        serviceHelper(ServiceHelper)

        service.genres = serviceHelper.genres
        service.includes = serviceHelper.includes
    }
}
Abhijit Sarkar
  • 21,927
  • 20
  • 110
  • 219

1 Answers1

1

Spring support in unit tests is rather minimal, and the ApplicationContext that's active doesn't really go through any of the lifecycle phases that it would in a running app, or even during initialization of integration tests. You get a lot of functionality mixed into your class when using @TestFor and/or @Mock, but it's almost entirely faked out so you can focus on unit testing the class under test.

I tried implementing org.springframework.beans.factory.InitializingBean just now and that worked, so you might get further with that.@Transactional will also be ignored - the "database" is a ConcurrentHashMap, so you wouldn't get far with that anyway.

If you need real Spring behavior, use integration tests. Unit tests are fast and convenient but only useful for a fairly limited number of scenarios.

Burt Beckwith
  • 75,342
  • 5
  • 143
  • 156
  • I actually don't need Spring for these tests which's why I didn't write an integration test. However, as I wrote in my question, even if I just instantiate the service class (new) and set the dependencies myself, ServiceUnitTestMixin kicks in and runs PostConstruct. If it didn't all'd be good. It seems like a bug that it does that even without a TestFor annotation. I don't want to implement InitializingBean interface because Spring recommends not to use it since a couple of years back. It'd be a step backward. – Abhijit Sarkar Dec 17 '14 at 04:28