Grails unit tests: Accessing defined beans via grailsApplication - grails

I have some (non-Grails-artifact) classes that access the service layer beans via passing around the grailsApplication object. However I'm having trouble unit testing the classes implemented in this way. Why doesn't the bean get registered in the main context?
#TestMixin(GrailsUnitTestMixin)
class ExampleTests {
void setUp() {}
void tearDown() {}
void testSomething() {
defineBeans {
myService(MyService)
}
assert grailsApplication.mainContext.getBean("myService") != null
}
}
The above code fails with:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'myService' is defined
What I'm trying to do is access services from plain old Java classes via the grailsApplication. This works, but not in unit test environment. Should I do it differently?
class POJO {
MyService myService;
public POJO(GrailsApplication grailsApplication) {
myService = (MyService) grailsApplication.getMainContext().getBean("myService");
}
}

The answer is that in the GrailsUnitTestMixin the applicationContext that holds your beans is set as the parentContext in the grailsApplication
beans.registerBeans(applicationContext)
static void initGrailsApplication() {
...
//the setApplicationContext in DefaultGrailsApplication set's the parentContext
grailsApplication.applicationContext = applicationContext
}
So you can get your beans with:
defineBeans {
myService(MyService)
}
assert applicationContext.getBean("myService")
assert grailsApplication.parentContext.getBean("myService")
EDIT
Today I faced the same problem, and my solution is:
#Before
void setup() {
Holders.grailsApplication.mainContext.registerMockBean("myService", new MyService())
}

In my case (grails 2.4.4) the accepted solution didn't work but pointed me in the right direction, this line worked instead as the bean factory in the mainContext within my unit test was an OptimizedAutowireCapableBeanFactory
Holders.grailsApplication.mainContext.beanFactory.registerSingleton('myBean', new MyBeanClass())

I have spent some time with the same issue, in my case running grails 2.2.4 and having (in src/groovy):
import grails.util.Holders
class SomeClass {
transient myService = Holders.grailsApplication.mainContext.getBean 'myService'
.....
}
Which is a bit different to question author, but at least it will be useful for someone coming from search engine results
Nevertheless accepted answer did not work for me, so I came up with a bit different approach of mocking and registering service used in SomeClass.
import grails.util.Holders
.. other imports
#TestMixin(GrailsUnitTestMixin)
class SomeClassTests {
#Before
void setUp() {
Holders.grailsApplication = grailsApplication
defineBeans {
myService(MyServiceMock)
}
}
....
}
class MyServiceMock extends MyService {
// overriden methods here
}

Related

Grails 4 service not being injected inside Grails Data Service

This is about a Grails service injected into a Data Service. The problem is that the injected service is null at runtime. Here is an example.
class MessagingService {
def sendEmail(String message) {
...
}
}
interface IFlowService {
...
}
#Service(Flow)
abstract class FlowService implements IFlowService {
MessagingService messagingService
void sendFoo() {
messagingService.sendEmail(message)
}
}
FlowService and MessagingService both reside under grails-app/services.
When FlowService calls sendEmail there is an NPE because messagingService is null.
MessagingService is hand-written and is not associated with a domain.
This project uses Grails 4.0.10 and the issue occurred several times. When the usual Gails magic (i.e. injection) didn't work I solved the first one or two issues with kludges, you know, just to avoid getting stuck.
Now it seems to me the issue is quite predictable, it happens every time I write a service not associated with a domain. Did I miss something in the documentation? What is the appropriate way to handle this?
Kludge: To get around the issue I include a method sayHi in the problematic service. It just logs a debug message. I invoke sayHi from BootStrap to check that it works. It does, surprisingly. Then I add code in BootStrap to assign the service to the supposedly injected property in the service. [Shudder]
I tried to reproduce the same-
interface IFlowService {
}
#Service(Flow)
abstract class FlowService implements IFlowService {
MessagingService messagingService
void hello() {
println "hello"
messagingService.hi() // <- NPE
}
}
class MessagingService {
void hi() {
println "hi"
}
}
This seems to be a bug to be in Grails. But you can easily solve this (probably as a workaround) by just adding #Autowired in the service-
import org.springframework.beans.factory.annotation.Autowired
#Service(Flow)
abstract class FlowService implements IFlowService {
#Autowired
MessagingService messagingService
void hello() {
println "hello"
messagingService.hi() // <- No NPE
}
}
It prints-

How to inject Grails services into src/groovy classes

Grails 2.4.x here. If I created a Grails service using grails create-service com.example.Widget, then how can I inject a reference of that service (a "bean") into a class under src/groovy?
This is actually not explained anywhere in the official Grails docs, and extensive searching turned back nadda.
1) You can use Spring Beans to inject a service into a non-artefact groovy file, using resources.groovy:
MyClass.groovy
class MyClass {
def widgetService
...
}
resources.groovy
beans = {
myclass(com.example.MyClass) {
widgetService = ref('widgetService')
}
}
2) There is also an additional #Autowired annotation that can do the same thing:
MyClass.groovy
import org.springframework.beans.factory.annotation.Autowired
class MyClass {
#Autowired
def widget
...
}
resources.groovy
beans = {
myclass(com.example.MyClass) {}
}
Notice - this time the myclass bean doesn't need the reference to the widget.
3) There is an alternative to injecting the WidgetService - using the Holders class to get the grailsApplication which will have a reference to the existing bean.
import grails.util.Holders
class MyClass {
def widgetService = Holders.grailsApplication.mainContext.getBean('widgetService')
...
}
**Update**
4) There is another option that is a hybrid of 1) and 2) -
Having the bean(s) injected by autowire=true within resources.groovy:
MyClass.groovy
class MyClass {
def widgetService
...
}
resources.groovy
beans = {
myclass(com.example.MyClass) { bean ->
bean.autowire = true
}
}
This is the approach I've been using locally as I feel it's the cleanest, but it does take more advantage of Grail's 'magic' (for better or worse).

Grails create a service from a factory

I would like to utilize a service written in Java in my Grails app using dependency injection. Creating it in Java without injection would look like this:
ServiceFactory.newInstance().getElementService()
I would like to use this in the same way services are injected for controllers, services, and jobs.
class ImportJob {
def elementService
...
}
I know this should go into resources.groovy and this is what I have so far:
serviceFactory(ServiceFactory) { bean ->
bean.factoryMethod = 'newInstance'
}
elementService(ElementService) {
}
I have found few resources in the documentation to help with this. How do I complete the elementService so it is creating the object as described above? Should I use a BeanBuilder?
You could create a FactoryBean for this since it's not as direct as calling a method in a class:
package com.mycompany
import org.springframework.beans.factory.FactoryBean
import org.springframework.beans.factory.InitializingBean
class ElementServiceFactoryBean implements FactoryBean<ElementService>, InitializingBean {
private ElementService elementService
ElementService getObject() { elementService }
Class<ElementService> getObjectType() { ElementService }
boolean isSingleton() { true }
void afterPropertiesSet() {
elementService = ServiceFactory.newInstance().elementService
}
}
and you'd register it in resources.groovy as
elementService(ElementServiceFactoryBean)
Use bean.factoryMethod and bean.factoryBean in the elementService bean.
serviceFactory(ServiceFactory) { bean ->
bean.factoryMethod = 'newInstance'
bean.scope = 'singleton'
}
elementService(ElementService) { bean ->
bean.factoryMethod = 'getElementService'
bean.factoryBean = 'serviceFactory'
}
This is a simple solution especially if ServiceFactory is external and cannot be changed.

Dependency injection not working inside Grails service

I have a class that I moved under the grails-app/services directory in order to inject the springSecurityService. This class is the implementation (Is that the proper terminology?) of the spring userDetailsService class. Here is my declaration in resources.groovy:
userDetailsService(com.company.product.PracticeUserDetailsService) {
grailsApplication = ref('grailsApplication')
}
This class is extending GormUserDetailsService.
My attempted dependencyInjection results in a null object.
class PracticeUserDetailsService extends GormUserDetailsService{
def springSecurityService
UserDetails loadUserByUsername(String username, boolean loadRoles) throws UsernameNotFoundException {
// impl omitted
}
}
If I create some test controller or some service in grails and inject the springSecurityService, it works fine. So, there is perhaps something about this particular class that is not placing it in the Grails ecosystem. I checked out this to try to manually inject it as follows:
beans = {
springSecurityTEST(grails.plugins.springsecurity.SpringSecurityService) {}
}
Move PracticeUserDetailsService from grails-app/services to src/groovy and change your Spring bean definition in resources.groovy to:
userDetailsService(com.company.product.PracticeUserDetailsService) {
grailsApplication = ref('grailsApplication')
springSecurityService = ref('springSecurityService')
}
For me it happened when I used GrailsApp.run(Application, args) to run the app...

Grails - Bootstrap - null pointers instead of services

I'd like to use data generator at init in my application. It works fine when create objects using .save() method, but it doesn't work when I want to use dedicated services, because of null pointers instead of injected services. That's my code:
I have defined DataGenerator bean inside conf/spring
beans = {
dataGenerator(DataGenerator)
}
My Bootstrap.groovy looks like:
class BootStrap {
def dataGenerator
def init = { servletContext ->
dataGenerator.generateData()
}
}
In `DataGenerator' I have:
class DataGenerator{
BookService bookService
def generateData() {
log.info("Generating books")
createBooks()
}
def createBooks(){
(1..40).each() {
CreateBookCommand command = new CreateBookCommand()
/* some command populate code*/
bookService.create(command);
}
}
}
The problem is, that I cannot invoke create() method, because bookService is always null
BookService is simple grails service with some dependencies, of course placed in grails-app/services
class BookService {
UserService userService
SpringSecurityService springSecurityService
def create(CreateBookCommand command){
Book book = new Book()
command.bindTo(book)
book.save(flush:true, failOnError:true)
}
/*some other methods*/
}
Could you tell me how to fix it?
Try this in resources.groovy
beans = {
dataGenerator(DataGenerator) { bean ->
bean.autowire = 'byName'
}
}
I assume DataGenrator being a class outside the grails artifact (that is: placed in src/groovy), you can refer the already available service class in the context as:
beans = {
dataGenerator(DataGenerator){
bookService = ref('bookService')
}
}
or try autowiring byName as mentioned by #sudhir.

Resources