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
}
}
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 aConcurrentHashMap
, 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.