Class.metaclass.static say can not get static on null - unit-testing

Was writing unit test cases and at one point I needed to do some meta programming to test a method as below.
void "test method:resolver"(){
setup:"mocked resolver"
ContextHolder.getMetaClass().static.getBean = {
Resolver resolver = Mock(Resolver)
resolver(_) >> {HttpServletRequest request1->
return 1;
}
}
and:"mocked getAppName"
CoreUtil.metaClass.static.getAppName = {
return "$apiName"
}
when:
UserGroupRole userGroupRole = service.resolve(username)
then:
userGroupRole != null
where:
apiName || username
"core-blog" || "test11"
}
Following are the scenarios that I have gone through for running test cases:
When running test case individually, It works perfectly.
When running test case as a whole Specification i.e. run the Specification class itself, It works perfectly
But when running the test cases as whole by
grails test-app :unit
It fails saying Class.metaclass.static say can not get static on null
Please help!

If you're making metaclass changes in your tests, you need to clean up those metaclass changes in a cleanup step at the end of each test. Otherwise you risk test pollution.
setup
metaclass work
when
then
cleanup:
revoke the metaclass changes here
where

Related

Unit test grails with domain objects using GORM functions

I have the following piece of code inside a service class named OrderService in Groovy on Grails. I want to make a unit test for this class. User and Order are domain classed. A user has many orders.
boolean testfun(long userId, lond orderId){
User user = User.findByUserId(userId)
if(user == null)return false
Order order = Order.findByUserAndId(user, orderId)
if(order == null)return false
return true
}
The unit test that I am trying to write is the following (using Spock):
#TestFor(OrderService)
#Mock([User, Order])
class OrderServiceSpec extends Specification{
def "test funtest"() {
User user = new User(2)
Order order = new Order()
order.metaClass.id = 3// I want to assign the id of the order in domain
order.save()
user.addToOrders(order)
user.save()
expect:
service.testfun(2,3) == true
}
}
However this test fails because the order is null. Can anyone help me?
Another question is: is this test a unit test? or should I write an integration test in grails?
It depends on what you're actually trying to test, but this can be a unit test—I'd just recommend modifying it a little bit to isolate only the service method that you're interested in testing. You're not looking to test the domain classes at all, so it's best to mock/stub the behavior that you need from them to test the service functionality.
A good way to do this is with Spock's support for interaction based testing via mock objects. Basically we specify that when the service's testfun() method is called, we expect User.findById() to be called once and Order.findByUserAndId() to be called once as well. Spock then allows us to stub out each method call so that we specify what we want the method to return. When we run the test, the stub will be used, not the actual GORM method.
Some complexity lies with stubbing out static methods (like GORM methods), but you can use a GroovySpy to get the job done.
Also, I'm assuming you meant to use User.findById() instead of User.findByUserId()?
Something along these lines should work for you:
def "test funtest"() {
setup:
// Global so that it replaces all instances/references of the
// mocked type for the duration of the feature method.
GroovySpy(User, global: true)
GroovySpy(Order, global: true)
when:
def result = service.testfun(2,3)
then:
// No need to return real objects, so use a mock
1 * User.findById(2) >> Mock(User)
1 * Order.findByUserAndId(_ as User, 3) >> Mock(Order)
result == true
when:
result = service.testfun(2,3)
then:
1 * User.findById(2) >> null
result == false
}
Note that we've isolated the service method. Any collaborating objects (User and Order) are only being interacted with via stubs and we can test the functionality of the service method without worrying about GORM at all.

Grails unit test using grailsApplication

I have a controller that on the save method calls a thread to retrieve some files. The thread has start() in a domain that has this line-
RetrievalThread retrievalThread = grailsApplication.mainContext.getBean ('retrievalThread').
In my unit test I tried this and it worked(I'll keep the other lines omitted that have no bearing right now). Without this line an error occurs saying can't get mainContext on null object,talking about grailsApplication. .
Def mainContext = Mock(ApplicationContext)
MainContext.getBean(_) >>{ name ->
return new MockRetrievalThread()}
The mock thread doesn't do anything.
This test runs fine but, any test after this fail with a null pointer exception with no real information. Looks like a bunch of background grails stuff. Is there a way to clean this up or use something better than what I'm using?
I'm sure there's a way to clean this up in a tearDown, but I think there is a better way.
1.) I would use DI rather than going through grailsApplication.mainContext.getBean; is there a reason you are doing it this way?
class MyController {
def retrievalThread
getFiles() {
return [files: retrievalThread.getFiles(params.id)]
}
}
2.a.) Using DI, you can then just set the controller's retrievalThread to a new instance of MockRetrievalThread within your test.
void "test getFiles"() {
given:
controller.retrievalThread = new MockRetrievalThread()
when:
params.id = 1
def returnedFiles = controller.getFiles()
then:
// assertions
}
2.b.) Or skip the MockRetrievalThread altogether and mock the retrievalThread bean using the mockFor method, and then set the mocked version to the injected instance in your controller.
void "test getFiles"() {
given:
def retrievalThreadMock = mockFor(RetrievalThread)
retrievalThreadMock.demand.getFiles { Integer input ->
return ['file1', 'file2', 'etc.']
}
controller.retrievalThread = retrievalThreadMock.createMock()
when:
params.id = 1
def returnedFiles = controller.getFiles()
then:
// assertions
}
You can use integration testing instead to run the entire app, in order to avoid any beans not being injected.
grails create-integration-test org.bookstore.Book

Grails : Spock : Unit testing GORM domain class hooks

Usually I was ending up writing test cases for a Domain by writing them for constraints and any custom methods(created by us in application) as we know we shouldn't test obvious.
But the time we started using coverage plugin, we found that our domains line of code is not fully covered which was due to gorm hooks(onInsert, beforeUpdate) that we never wrote test cases for.
Is there a way we can test these. One possible way that seems obvious but not suitable is to call another method(containing all code which was earlier in hooks) within these hooks and test that method only and be carefree for hooks.
Any solutions...
Edit
Sample code in domain that I want to unit-test:
class TestDomain{
String activationDate
def beforeInsert() {
this.activationDate = (this.activationDate) ?: new Date()//first login date would come here though
encodePassword()
}
}
How can I unit-test beforeInsert or I would end up writing integration test case?
Perhaps a unit test like:
import grails.test.mixin.TestFor
#TestFor(TestDomain)
class TestDomainSpec extends Specification {
def "test beforeSave"() {
given:
mockForConstraintsTests(TestDomain)
when:
def testDomain = new TestDomain().save(flush:true)
then:
testDomain.activationDate != null
}
}

Grails 2.4.4 : How do mock a transient service inside a domain?

I have been trying to figure this out for 2 days now and I am really stuck and frustrated. I have a domain object with a service which is being used for custom validation. The domain looks like this:
class Llama {
String name
transient myFetcherService
static transients = [
'myFetcherService'
]
static constraints = {
name validator: { val, obj ->
if (obj.nameExists(val) == true) {
//return some error here.
}
}
}
protected boolean nameExists(String name) {
List<Llama> llamasList = myFetcherService.fetchExistingLlamasByName(name)
if (llamasList.isEmpty()) {
return false
}
return true
}
}
Now, I have another Service, which simply saves a list of Llama objects. It looks like this:
class LlamaFactoryService {
public void createLlamas(List<String> llamaNames) {
llamaNames.each { name ->
new Llama(name: name).save()
}
}
}
In my test. I keep getting this error:
Failure: createLlamas should create Llammas (com.myLlamaProject.LlamaFactoryServiceSpec)
| java.lang.NullPointerException: Cannot invoke method myFetcherService on null object
I don't understand. In my tests, added a metaClass for the service in the "given" section. When it tries to save, it's telling that the service is null. This is what my test looks like:
given:
def myFetcherService = mockFor(MyFetcherService)
myFetcherService.demand.fetchExistingLlamasByName {def name -> return []}
Llama.metaClass.myFetcherService = myFetcherService.createMock()
when:
service.createLlamas(['Pablo','Juan','Carlos'])
then:
//some validations here....
I also tried using metaClass on the method nameExists() like:
Llama.metaClass.myFetcherService = { def name -> false }
, but it gives me the same nullPointerException as the one above. Could someone point me to the right direction? I'm a bit stuck. :(
Thanks in advance for reading and helping.
You're using a unit test and the general rule for unit tests is that beans generally aren't created for you, so you'll need to inject them yourself.
(Code edited to reflect the fact I misread the question)
I think you want a testing pattern something like:
given:
def mockMyFetcherService = Mock(MyFetcherService) // create the mock
Llama.metaClass.getMyFetcherService = { mockMyFetcherService } // inject the dependency
def returnList = [] // let's just define this here and you can re-use this pattern in other tests more easily
when:
service.createLlamas(['Pablo','Juan','Carlos'])
then:
// tell Spock what you expect to have happen with your Mock - return the List you defined above
3 * mockFetcherService.fetchExistingLlamasByName(_) >> returnList
If the injection of the service into the metaClass doesn't work (suggested here), you could always try using the defineBeans{} closure within the unit test itself (http://www.block-consult.com/blog/2011/08/17/inject-spring-security-service-into-domain-class-for-controller-unit-testing/).
Thus you could try:
defineBeans {
myFetcherService(MockMyFetcherService)
}
where MockMyFetcherService is defined in the same file that defines the test. This is the approach followed here:
See here for examples of more Spock interactions.
If you're using Grails 2.4.3 or below you'll need to put CGLIB in BuildConfig.groovy but I see here that it's already done for you in 2.4.4, so you should be ok just to use Mock(classname).

What is the correct place to put mock demand statements in Grails tests

I am working with grails and writing tests using Spock framework.
I am trying to figure out what is the correct section (given, where, then, setup ...) in the test to put mock code.
For example, is the following correct?
void "test Something"() {
given:
//build mock and add demand statements...
when:
//Call method
}
I tend to put my demands in the then section unless I have complex mocks in which case I put them in the given, but they will work both places.
void "test Something"() {
given:
def myService = Mock(MyService)
mainThing.myService = myService
when:
mainThing.doCall()
then:
1 * myService.call() >> 'value'
}