Search code examples
javaunit-testingjunitmockito

Mocking a dependency on a property file


I'm trying to write a unit test that involves using legacy code. Problem is, from what I can tell, the legacy code uses a key/value pair from a property file to initialize one of its final static private members, and I haven't the slightest as to where that property file might be (the entire application is quite huge).

So, in my test, I want to do something like this (using Mockito):

LegacyClass legacyClass = mock(LegacyClass.class);

I end up getting a ExceptionInInitializationError which indicates it can't find a certain property key.

In LegacyClass.java, there's:

private static final int LEGACY_PROPERTY = 
    Integer.parseInt(LegacyPropertyManager.getProp("legacy.property.key"));

Is there a way to write a test that uses this legacy class, even if the property key it's looking for doesn't exist? Can it be mocked somehow?


Solution

  • You might not get very far without bytecode manipulation , which used to require a clever library like PowerMock but is now available in Mockito 5+ by default or 2+ as an opt-in.

    Note that your LegacyClass.java initializes this property in a static final field, which means that the initializer will run as soon as it's loaded. PowerMock uses deeper magic (read: bytecode manipulation) to allow you to mock the static getProp method you cited above. Mockito 5+ rewrites the class using Java instrumentation to achieve the same effect.

    This answer was originally written for PowerMock, which required some careful setup and didn't always have strong documentation. Mockito's documentation for mocking static calls is pretty robust but you can also see other answers on Stack Overflow.

    For the PowerMock version, you'll need to do the following to get started:

    @RunWith(PowerMockRunner.class)
    @PrepareForTest(LegacyPropertyManager.class)
    public class YourClass {
    
      @Before public void stubLegacyPropertyManager() {
        Mockito.when(LegacyPropertyManager.getProp("legacy.property.key"))
            .thenReturn("42");
      }
    
      @Test public void yourTest() {
        // ...
      }
    }
    

    Note the class-level annotations, which respectively allow for PowerMock initialization and register the correct class for static-level mocking.