How to overload / override static method to return an other value?

Basically I'm trying to mock a static class for unit testing.

Example:

class Library {
    public static boolean isActivated() {
        return false;
    }
}

class Test {
    public static void main(String[] args) {
        // some magic
        
        if (Library.isActivated()) {
            System.out.println("'some magic' works!");
        } else {
            System.out.println("fail");
        }
    }
}

What would some magic need to be, to make Library.isActivated() return true.

Is there some special way to do this without changing the source code of Library?

As far as I know this is not possible in java but I'm not very familiar with Reflection I thought this might be possible with it.


Solution 1:

You definitely cannot override a static method. However, you can mock a static method with a lot of work. Generally, mocking a static method isn't a good sign. Fortunately, there are libraries out there that can do this if you need it.

Mockito has added support for this and there is a pretty good tutorial from Baeldung demonstrating how to do this: https://www.baeldung.com/mockito-mock-static-methods#mocking-a-no-argument-static-method.

Based on the tutorial:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>4.2.0</version>
    <scope>test</scope>
</dependency>
@Test
void mockLibraryIsActivated() {

    // Before mocking the static method is going to return false
    assertFalse(Library.isActivated());

    // Using MockedStatic to mock the method
    try (MockedStatic<Library> utilities = Mockito.mockStatic(Library.class)) {
        utilities.when(Library::isActivated).thenReturn(true);

        // Perform your test, the mock only works within the try block
        assertTrue(Library.isActivated());
    }

    // Mock is no longer active
    assertFalse(Library.isActivated());
}

The one key limitation to this is that the mock only applies within the code block it is defined in. So if you had another unit test you would also have to mock it within that unit test.

If you really want to dive down the rabbit hole you can look at how MockitoCore.mockStatic is implemented in the GitHub repo: https://github.com/mockito/mockito/blob/main/src/main/java/org/mockito/internal/MockitoCore.java.