简体   繁体   中英

Grails dynamic methods not present when running integration tests

I'm working on a project using Grails 2.5.4 and I'm currently trying to run some integration tests that are not running. I've debugged the issue and found that apparently some dynamic methods on the services to be tested are not there when running in an integration test (if you run that in the context of the application the methods are there and everything works). This happens in many of the test I'm trying to run, I've choose one as an example but the others that are failing have the same problems.

I have this domain class

class Event {
...
    static hasMany = [
        bundles : Bundle
    ]
...    
}

and a service method to be tested:

@Transactional
class BundleService {
...
    void assignEvent(Event event, List bundleIds) {
    ..
        for (id in bundleIds) {
            event.addToBundles(Bundle.get(id))
        }
    }
...
}

So then I run this spock test

class BundleServiceIntegrationSpec extends Specification {

    BundleService bundleService
    EventService  eventService
    private BundleTestHelper bundleHelper = new BundleTestHelper()

    ...

    void '04. Test deleteBundleAndAssets method'() {
    when: 'a new Bundle is created'
        Bundle bundle = bundleHelper.createBundle(project, 'Test Bundle')
    and: 'a new Event is created'
        Event event = eventService.create(project, 'Test Event')
    and: 'the above Bundle is assigned to the Event'
        bundleService.assignEvent(event, [bundle.id])
    ...
}

it fails in the line moveEvent.addToBundles(Bundle.get(id)) of BundleService with the following exception

groovy.lang.MissingMethodException: No signature of method: 
net.domain.Event.addToBundles() is applicable for argument 
types: (net.domain.Bundle) values: [Test Bundle]
Possible solutions: getBundles()
at net.service.BundleService.$tt__assignEvent(BundleService.groovy:101)

The problem is that the method addToBundles() that should be added dynamically by Grails to the Event class because of the hasMany collection "bundles" is not added. As I mentioned, if you run the application and use this service the method is there and everything works.

I tried changing the base class of the test (from Specification to IntegrationSpec) since I belive here is where the dynamic capabilities as well as transaction management and other things for integration tests are managed, but it didn't worked.

Is there any reason why this method that should be there in the service is not present in the context of integration tests? Thanks

You are missing grails.test.mixin.Mock annotation in your test class. Grails unit test uses this mixin to generate all domain related methods for a class so you can use this domain correctly in the unit test. Something like this should do the trick:

@Mock([Event])
class BundleServiceIntegrationSpec extends Specification {

    BundleService bundleService
    EventService  eventService
    private BundleTestHelper bundleHelper = new BundleTestHelper()

    ...

    void '04. Test deleteBundleAndAssets method'() {
    when: 'a new Bundle is created'
        Bundle bundle = bundleHelper.createBundle(project, 'Test Bundle')
    and: 'a new Event is created'
        Event event = eventService.create(project, 'Test Event')
    and: 'the above Bundle is assigned to the Event'
        bundleService.assignEvent(event, [bundle.id])
    ...
}

More about testing domain classes can be found here: https://grails.github.io/grails2-doc/2.4.5/guide/testing.html#unitTestingDomains

@Szymon Stepniak Thanks for your answer, and sorry for the late reply. I've tested what you proposed but it didn't work. Later I've read that the grails.test.mixin.Mock annotation is only for unit tests, and it should not be used in integration tests. This is also true for @TestFor and @TestMixin annotations as well (I've read about this in this post ).
So after this a collegue at work proposed me to search for this kind of annotations in other tests thinking that maybe that could lead to some kind of test pollution between tests, and after removing a @TestFor annotation in one of the tests that ran previously as part of the whole integration test suite, the failing test that I posted started working. The strangest thing (appart from the compiler not complaining about this) is that the offending test (the one from which I removed the @TestFor annotation) was passing all green, it wasn't even failing!
So if someone has a similar problem I suggest to search for this kind of unit test annotations anywhere in the whole integration tests suite and remove it because the compiler won't complain, but in my experience it could have influence on other tests and it can lead to very strange behaviour.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM