Skip to main content
Blog

Grails, private method scope and mocks

By 16 september 2014januari 30th, 2017No Comments

A simple test

Since I wanted to have some test coverage (legacy code alert!) for my project I started out testing one of the services, a grails artefact.
All was well, I’m using Spock and testing is a breeze.

At some point I wanted to have another component to return a fixed value so I would have something predictable to test with, so I introduced a Mock.
The mock is supposed to return some data that is predictable.

/*
 * Something like this:
 * (yes I like declaring a type for my variables):
 */
MyComponent component = Mock(MyComponent)

...

given:
component.getData() >> {
   return "fixed values are simpler"
}

Well, that didn’t work…

| Failure:  test(test.MyComponentTest)
|  Condition not satisfied:
result == "testvalue"
|      |
null   false
	at test.MyComponentTest.test(MyComponentTest.groovy:26)

Null is returned, so somehow the recorded behaviour is not working.

After checking a few thing such as:

  • is it a final method?
  • is it a final class?
  • is there method overloading that I’m missing? (note default value arguments!)
  • wrong imports perhaps?
  • or just a typo?

I then checked whether the method was private, and to my surprise it was! This code is in production, works, and still a private method is being called from outside the class (breaking encapsulation etc). Well that was new to me.

The private keyword

In groovy, in principle, just like in java, the private keyword means exactly that what you would expect. A private method is only accessible from within a class and not from the outside, nothing strange there.
In practice though, it’s not that simple. Private methods can often be easily called from outside the class, due to (for example) the following bugs:

In short, one could say that groovy does not care about your silly method access visibility. Anything can be accessed -usually-, it is up to the developer to decide whether it is the right thing to do (a ‘suggestion’ of accessibility).

Why make a big deal out of it?

When dealing with mocking frameworks, the private keyword becomes important again. Spock, in this case, does respect the keyword! This is probably because spock is not only meant to be used with groovy, but also with Java and other JVM languages.

Ok now what…

In our case it was simple. The method was being used as if it were public, so we removed the access modifier making it package visibility and mockable.
Newer versions of Spock allow for using GroovyMock() which might in some cases help out, not in ours though. The private method is still not mockable.
You might want to rethink your code structure if an import part of the flow relies on accessing private methods from the outside, it requires some investigation.

The bug reports’ follow-ups mention that in the future, groovy might start supporting private visibility. Maybe in a major version update (grails 3.0). For now though, it won’t happen since a lot of code is relying on the undocumented feature and would break instantly.