Grails unit tests: Accessing defined beans via gra

2019-05-26 03:14发布

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");
  }
}

3条回答
Fickle 薄情
2楼-- · 2019-05-26 03:50

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())
查看更多
女痞
3楼-- · 2019-05-26 03:52

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
}
查看更多
\"骚年 ilove
4楼-- · 2019-05-26 04:00

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())
}
查看更多
登录 后发表回答