0

I have a class which contains an public static method getProduct(String name):

public class ProductManager {
  public static Product getProduct(String name) {
        Product prod = findProduct(name);
        return prod;
  }
}

Another CustomerService class use the above ProductManager:

public class CustomerService {
   ...
   public void handleProduct() {
     Product appleProd = ProductManager.getProduct("apple");
     doHandle(appleProd);
   }
}

I unit test handleProduct() method in CustomerService class. I use mockito to mock the ProductManager.getProduct("apple") part in test:

public class CustomerServiceTest {
  @Test
  public void testHandleProduct() {
    Product mockProd = Mockito.mock(Product.class);

    // MissingMethodInvocationException
    when(ProductManager.getProduct("apple")).thenReturn(mockProd);
    ...
  }
}

However, when I run my test, I got MissingMethodInvocationException from Mockito:

org.mockito.exceptions.misusing.MissingMethodInvocationException: 
when() requires an argument which has to be 'a method call on a mock'.
For example:
    when(mock.getArticles()).thenReturn(articles);

Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
   Those methods *cannot* be stubbed/verified.
   Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.

It complains that inside when() I don't call method, but I do call the public static method ProductManager.getProduct("apple") in when(...), why Mockito rise this error to me ? I don't understand.

user842225
  • 5,445
  • 15
  • 69
  • 119

1 Answers1

1

Mockito cannot mock static methods. Make it an instance method and your code will work.

There are other frameworks that allow that (e.g. Powermock), however this is rather bad practice and a sign of bad design. You should create an instance and do dependency injection. If a method is so small that it can be tested indirectly while testing other class (e.g. Math.max()), than there is no need for mocking.

In the code you posted you have getProduct(), but in the stack trace it is getArticles() - I assume that the code was just a simplified example, while the stack trace is actual.

Here are a few articles explaining the problem of testing/mocking static methods:

Community
  • 1
  • 1
Jaroslaw Pawlak
  • 5,538
  • 7
  • 30
  • 57
  • That is stupid. Static method is completely untestable with mockito? Is there any workaround to test static method in mockito? Yes, getArticles() are examples from mockito when it rise the exception. – user842225 Nov 09 '15 at 10:12
  • You cannot do this with Mockito and you shouldn't be doing this anyway. See my edited answer. – Jaroslaw Pawlak Nov 09 '15 at 10:14
  • I see your edited answer, you said it is a bad design to have public static function, but you didn't give a reason why it is bad design? What is bad from public static method in my case? If you could explain further it would be great. – user842225 Nov 09 '15 at 10:16
  • Also, factory method is normally public static, I don't see why it is bad to have public static method in a class. I think if Mockito doesn't support mocking public static method, it is their problem, it doesn't mean I have bad design. – user842225 Nov 09 '15 at 10:18
  • You test factory methods indirectly - you don't mock them. I have added a few links to various articles explaining the problem. Hope it helps. – Jaroslaw Pawlak Nov 09 '15 at 10:20
  • Please check my new question here : http://stackoverflow.com/questions/33610230/use-mockito-to-unit-test-a-function-which-contains-static-method-call-async-ta , If I don't mock the static method, how can I test it then?? – user842225 Nov 09 '15 at 13:32