11

I'm trying to write some Spock tests with Groovy to test some Java code (specifically a servlet Filter). I have some private static and private static final variables that I would like to mock, but I can't determine if there is a way to do this. I know metaClass is available for methods, is there anything similar for variables?

For instance, I have:

public class MyFilter implements Filter {
  private static WebResource RESOURCE;
  private static final String CACHE_KEY = "key-to-be-used-for-cache";
  ... actual methods, etc ...
}

I've tried using Mock(MyFilter), as well as using Java reflection to change the value (based on this question and answer Change private static final field using Java reflection).

I would like to do this without adding something like Mockito or other frameworks, if that's possible, just use plain Groovy and Spock.

Thanks for any ideas!

UPDATE 1

At least for private static variables I did get the following to work:

Field field = MyFilter.class.getDeclaredField("CACHE_KEY")
field.setAccessible(true)
field.set(null, "new-key-value")

But I still haven't been able to get around the final aspect.

UPDATE 2

Thanks to Xv. I can now set this with the following:

Field field = MyFilter.class.getDeclaredField("CACHE_KEY")
field.setAccessible(true)

Field modifiersField = Field.class.getDeclaredField("modifiers")
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

field.set(null, "new-key-value")
Community
  • 1
  • 1
mnd
  • 2,709
  • 3
  • 27
  • 48
  • I guess it depends on how it's being tested, but IMO using a framework designed to do what you're trying to do is the better approach, and more broadly applicable, e.g., http://java.dzone.com/articles/mocking-static-methods-groovy and http://stackoverflow.com/a/15834010/438992 etc. – Dave Newton Dec 18 '14 at 17:49
  • Thanks for your comment @DaveNewton - especially with Peter Niederwieser stating that only groovy defined methods can be mocked in Spock. My case is specific to class fields/variables, but I'll check to see if one of the other frameworks would be able to do this for me. Thanks. – mnd Dec 18 '14 at 17:59
  • 2
    I know it is not what you are looking for, but a while ago I played around with the combination of [Spock and PowerMock](https://github.com/kriegaex/Spock_PowerMock) to mock static methods. I don't remember if it also works for (final) static members, just try for yourself. But what I actually want to say is that if your code is so hard to test, you should not upgrade your tests or test tools but refactor the code for testability. I think whenever you need tricks like the ones you want or tools to give you what you want, this is a **code smell**. – kriegaex Dec 18 '14 at 23:41
  • Why without adding other frameworks? Any particular reason? – kazanaki Apr 01 '15 at 15:51
  • The main issue is that it seems a lot of frameworks can handle one difficult testing scenario (mocking finals, mocking constructors, etc.), and in the past I've tried adding each framework to get the one piece I need, and that just makes a mess. I'd prefer to keep the dependencies as minimalistic as possible - which will also help reduce the different coding paradigms introduced by each of the different frameworks. – mnd Apr 01 '15 at 17:23

2 Answers2

12

Based on what I learned from https://stackoverflow.com/a/25031713/239408, this works for me in spock

import java.lang.reflect.Field
import java.lang.reflect.Modifier

...

    def setup() {

        Field field = BackendCredentials.getDeclaredField("logger")
        field.setAccessible(true);

        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

        field.set(null, Mock(Logger))
    }

Looks like you are missing the unsetting of the Modifier.FINAL flag.

Community
  • 1
  • 1
xverges
  • 4,608
  • 1
  • 39
  • 60
0

Either you need to use PowerMock (or another similar solution), or refactor your code. Spock does not support mocking of private/static/final methods on its own. This limitation is also present in Mockito, so that must give you a hint on best-practices.

kazanaki
  • 7,988
  • 8
  • 52
  • 79