我有一个类,它包含公共静态方法getProduct(String name)
:
public class ProductManager {
public static Product getProduct(String name) {
Product prod = findProduct(name);
return prod;
}
}
另一个CustomerService
类使用上面的ProductManager
:
public class CustomerService {
...
public void handleProduct() {
Product appleProd = ProductManager.getProduct("apple");
doHandle(appleProd);
}
}
我在CustomerService
类中对handleProduct()
方法进行了单元测试。我使用mockito来模拟测试中的ProductManager.getProduct("apple")
部分:
public class CustomerServiceTest {
@Test
public void testHandleProduct() {
Product mockProd = Mockito.mock(Product.class);
// MissingMethodInvocationException
when(ProductManager.getProduct("apple")).thenReturn(mockProd);
...
}
}
然而,当我运行测试时,我从Mockito得到了MissingMethodInvocationException
:
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.
它抱怨在when()
内部我不调用方法,但我在when(...)
中调用了公共静态方法ProductManager.getProduct("apple")
,为什么Mockito向我提出这个错误?我不明白。
Mockito不能模拟静态方法。将它作为一个实例方法,您的代码就可以工作了。
还有其他框架允许这样做(例如Powermock),但这是一种相当糟糕的做法,也是糟糕设计的标志。您应该创建一个实例并进行依赖项注入。如果一个方法很小,可以在测试其他类(例如Math.max()
)的同时进行间接测试,那么就没有必要进行嘲讽。
在您发布的代码中,您有getProduct()
,但在堆栈跟踪中是getArticles()
——我认为该代码只是一个简化的示例,而堆栈跟踪是实际的。
以下几篇文章解释了测试/模拟静态方法的问题:
- https://softwareengineering.stackexchange.com/questions/231594/mocking-static-methods
- http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/
- http://blog.christianposta.com/testing/java-static-methods-can-be-a-code-smell/
- 为什么Mockito不模拟静态方法