Baiqing
Baiqing

Reputation: 1343

Inject inline Mockito static methods

I am testing a class using JUnit4 and the target class uses a dependency static method to create an object, here is the relevant snippet of code from the target class:

private static final Dependency DEPENDENCY_CLIENT = Dependency.getInstance();

I know that since version 3.4.0 of Mockito, there is the added ability to mock static methods, for example, I can do something like:

try (MockedStatic<Dependency> mocked = mockStatic(Dependency.class)) {
  mocked.when(Dependency::getInstance).thenReturn(dependency);
  Dependency test = Dependency.getInstance();
  mocked.verify(Dependency::getInstance);
}

The dependency variable is just a simple mocked version of that class.

However, the class I want to test makes this call in its constructor, so is there a way where I can make my target class call the mocked getInstance() method during its initialization?

Upvotes: 0

Views: 1382

Answers (1)

tgdavies
tgdavies

Reputation: 11464

I'm not exactly sure what problem you are having. The code below works for me (I'm using JUnit 5, but that should make no difference)

@ExtendWith(MockitoExtension.class)
public class MockEg {
    static class Dependency {
        public static Dependency getInstance() {
            return new Dependency();
        }
        public String getMessage() {
            return "I am not a mock";
        }
    }

    static class ClassToTest {

        private final Dependency dependency;
        public ClassToTest() {
            this.dependency = Dependency.getInstance();
        }

        public String getDependencyMessage() {
            return dependency.getMessage();
        }
    }

    @Test
    public void aTest() {
        try (MockedStatic<Dependency> mocked = mockStatic(Dependency.class)) {
            Dependency dependency = mock(Dependency.class);
            when(dependency.getMessage()).thenReturn("I am a mock");
            mocked.when(Dependency::getInstance).thenReturn(dependency);
            ClassToTest c = new ClassToTest();
            assertThat(c.getDependencyMessage(), Matchers.is("I am a mock"));
            mocked.verify(Dependency::getInstance);
        }
    }
}

The right way to deal with this situation is to decouple your class from statics, by introducing an interface which you can mock:

    interface DependencyProvider {
        Dependency getDependency();
    }
    
    class ClassToTest2 {

        private final DependencyProvider dependencyProvider;
        public ClassToTest2(DependencyProvider dependencyProvider) {

            this.dependencyProvider = dependencyProvider;
        }

        public String getDependencyMessage() {
            return dependencyProvider.getDependency().getMessage();
        }
    }

Upvotes: 1

Related Questions