0

I have a class named SpecialClass. This class has the method doSomething in it. This class is in this particular manner special, that I do not want to mock this class at all via MockedStatic. It is very easy for me to remeber that I don't want to mock this class, but there are other people programming at the same project and they should know to not mock this class but I can not relate on it.

Given this special test:

@Test
void testSomething(){
    try(MockedStatic<SpecialClass> mock = Mockito.mockStatic(SpecialClass.class)){

        mock.when(SpecialClass::doSomething).thenReturn(0);

         System.out.println(SpecialClass.doSomething());
    }
}

I dont want to let this test execute at all. But it will execute, because Mockito does not know about my SpecialClass and not to mock it. There could be also various other locations where SpecialClass could be mocked.

Some classes can not be mocked because of Mockito decides so. Given this mock of java.lang.System:

@Test
void testFail(){
    try(MockedStatic<System> sys = Mockito.mockStatic(System.class)){
        // some code
    }
}

I get the exception org.mockito.exceptions.base.MockitoException: It is not possible to mock static methods of java.lang.System to avoid interfering with class loading what leads to infinite loops, which is ok.

My question is: Can I somehow have some global project settings (or some annoations) to mark my class SpecialClass to be not used in Mockitos MockedStatic? I would be also ok if I can also not mock this class in a normal way.

I tried to find some information regarding restricting mocks, but i was unable to find some.

My mockito version of mockito-core and mockito-inline is 4.3.1

alea
  • 980
  • 1
  • 13
  • 18
  • 1
    I would suggest that if you aren't able to communicate expected usage of the class with other people on the same project - whether that's via Javadocs, email, team meetings, documentation or whatever - then the problem is more of a communication one than a technical one. – Jon Skeet Feb 09 '22 at 15:30
  • @JonSkeet The problem is that I would like to prevent it programmatily. Javadoc can be ignored and is not always read, emails or documentations can be forgotten. A easier way in my opinion would be when trying to execute the test. I see that a Javadoc hint in the `SpecialClass` would be good, but better would be an automatic way of letting other programmers know that they used the mocking of this class wrong. – alea Feb 09 '22 at 17:50
  • My point is that if you can't trust your team-mates to pay attention to team conventions etc, there are bigger problems. Heck, you could always have a run-once-a-day job that searches for `mockStatic(SpecialClass.class)` in the codebase if you want to have *some* automated protection... – Jon Skeet Feb 09 '22 at 17:58

1 Answers1

0

If you have control over the class, you can use the annotation @DoNotMock (official javadoc). It can be placed over an class to prevent the mocking of the class.

That means that the class can look like this.

@DoNotMock(reason = "Use a real instance instead")
class SpecialClass {
    // ...
}

If you try to mock this class, you will get an error and the reason you have provided will be given to you.

You will need to have control over the class, since you need to place the annoation over it.


The following is a less suboptimal solution, which should be only considered when you do not have control over the class.

I used a junit test to read all my files and trying to detect all mocks. Please note that my test is working in a very special assumption that all of my test classes are in the same directory. This will hoever not be given in every project. In this case you will need to find the files recursivly.

class NoStaticMockTest {

    @Test
    void testNoMocks() throws IOException {
        // Base dir of my tests
        File testDir = new File("src/test/java");
        // reading all Files in the test directory excluding this file
        for (File file : testDir.listFiles(pathname -> !pathname.getAbsolutePath().endsWith("NoStaticMockTest.java") && pathname.isFile())) {
            try (FileInputStream fis = new FileInputStream(file)) {
                // Reading the contennt and trying to find MockedStatic<SpecialClass>
                String content = IOUtils.toString(fis);
                if (content.contains("MockedStatic<SpecialClass>")) {
                    Assertions.fail(file.getAbsolutePath() + " used MockedStatic<SpecialClass> which is not allowed");
                }
            }
        }
    }

}
alea
  • 980
  • 1
  • 13
  • 18