284
votes

I read a few threads here about static methods, and I think I understand the problems misuse/excessive use of static methods can cause. But I didn't really get to the bottom of why it is hard to mock static methods.

I know other mocking frameworks, like PowerMock, can do that but why can't Mockito?

I read this article, but the author seems to be religiously against the word static, maybe it's my poor understanding.

An easy explanation/link would be great.

7
Just a side-note: PowerMock is not a mock object library per-se, it just adds those features (mocking statics and ctors) on top of other libraries. We use PowerMock+Mockito at work they float well with each other.Matthias

7 Answers

248
votes

I think the reason may be that mock object libraries typically create mocks by dynamically creating classes at runtime (using cglib). This means they either implement an interface at runtime (that's what EasyMock does if I'm not mistaken), or they inherit from the class to mock (that's what Mockito does if I'm not mistaken). Both approaches do not work for static members, since you can't override them using inheritance.

The only way to mock statics is to modify a class' byte code at runtime, which I suppose is a little more involved than inheritance.

That's my guess at it, for what it's worth...

25
votes

If you need to mock a static method, it is a strong indicator for a bad design. Usually, you mock the dependency of your class-under-test. If your class-under-test refers to a static method - like java.util.Math#sin for example - it means the class-under-test needs exactly this implementation (of accuracy vs. speed for example). If you want to abstract from a concrete sinus implementation you probably need an Interface (you see where this is going to)?

15
votes

Mockito [3.4.0] can mock static methods!

  1. Replace mockito-core dependency with mockito-inline:3.4.0.

  2. Class with static method:

    class Buddy {
      static String name() {
        return "John";
      }
    }
    
  3. Use new method Mockito.mockStatic():

    @Test
    void lookMomICanMockStaticMethods() {
      assertThat(Buddy.name()).isEqualTo("John");
    
      try (MockedStatic<Buddy> theMock = Mockito.mockStatic(Buddy.class)) {
        theMock.when(Buddy::name).thenReturn("Rafael");
        assertThat(Buddy.name()).isEqualTo("Rafael");
      }
    
      assertThat(Buddy.name()).isEqualTo("John");
    }
    

    Mockito replaces the static method within the try block only.

3
votes

Mockito returns objects but static means "class level,not object level"So mockito will give null pointer exception for static.

3
votes

As an addition to the Gerold Broser's answer, here an example of mocking a static method with arguments:

class Buddy {
  static String addHello(String name) {
    return "Hello " + name;
  }
}

...

@Test
void testMockStaticMethods() {
  assertThat(Buddy.addHello("John")).isEqualTo("Hello John");

  try (MockedStatic<Buddy> theMock = Mockito.mockStatic(Buddy.class)) {
    theMock.when(() -> Buddy.addHello("John")).thenReturn("Guten Tag John");
    assertThat(Buddy.addHello("John")).isEqualTo("Guten Tag John");
  }

  assertThat(Buddy.addHello("John")).isEqualTo("Hello John");
}
2
votes

I seriously do think that it is code smell if you need to mock static methods, too.

  • Static methods to access common functionality? -> Use a singleton instance and inject that
  • Third party code? -> Wrap it into your own interface/delegate (and if necessary make it a singleton, too)

The only time this seems overkill to me, is libs like Guava, but you shouldn't need to mock this kind anyway cause it's part of the logic... (stuff like Iterables.transform(..))
That way your own code stays clean, you can mock out all your dependencies in a clean way, and you have an anti corruption layer against external dependencies. I've seen PowerMock in practice and all the classes we needed it for were poorly designed. Also the integration of PowerMock at times caused serious problems
(e.g. https://code.google.com/p/powermock/issues/detail?id=355)

PS: Same holds for private methods, too. I don't think tests should know about the details of private methods. If a class is so complex that it tempts to mock out private methods, it's probably a sign to split up that class...

0
votes

In some cases, static methods can be difficult to test, especially if they need to be mocked, which is why most mocking frameworks don't support them. I found this blog post to be very useful in determining how to mock static methods and classes.