Grails clean global mock on integration tests to avoid polluted environment

So, you are using Grails/Groovy for your app and Spock as testing framework. You have an integration test that is testing something on a class that has another dependencies that you have to mock. Something like:

class TestedClassSpec extends Specification {

    @Unroll
    void "test some method on Class that has dependencies"() {
        given:
        def testedClass = new TestedClass()
        GroovyMock(DependentClass, global: true)
        
        when: "we do something on the class"
        testedClass.doSomething()

        then: "something is done"
        def result = somethingHasHappened

    }
}

Just a little addendum here: in Spock, everything that is instantiated on given: block is not cleaned with the transaction, you have to take care of.

All fine for now, but after some months we add a test on the dependency class. Maybe something like:

class DependencyClassSpec extends Specification {

    @Unroll
    void "test some method on DependencyClass"() {
        given:
        def testedClass = new DependencyClass()
        
        when: "we do something on the class"
        testedClass.doSomething(wz)

        then: "something is done"
        def result = xy
    }
}

At this point, our test is failing, returning always a null object when DependencyClass is instantiated. This happens because the empty global mock on the first tested class is now polluting the environment and the second test, instead of instantiating the new class and call the method, will call the empty global instance, hence the return of the null.

Worst yet, imagine that the second test class is already on your solution, passing the test and all of the sudden is not passing anymore. This scenario will arise, let’s say when you add another integration test class that will change the order of execution for the integration tests, so that the mocking test is now executed before others, pollute the environment and lets you wandering what happen with your second test class that you didn’t even touch, before passing, now failing.

The solution for this problem is to clean the environment after using the globally mocked dependency class. You can do that either on [shell]cleanup:[/shell] part of the the test if the global mock is instantiated at test level([shell]given:[/shell]), or on [shell]cleanup()[/shell] if the global mock is instantiated at test class level([shell]setup()[/shell]).

You will remove the class like:

cleanup:
    GroovySystem.metaClassRegistry.removeMetaClass NameOfThePollutingClass

This will remove only the instance of the class, not all the meta class, so no worry, is safe.

Have fun.

One thought on “Grails clean global mock on integration tests to avoid polluted environment

Leave a Reply

Your email address will not be published. Required fields are marked *