Java org.mockito.exceptions.misusing.MissingMethodInvocationException

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22873419/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 18:36:13  来源:igfitidea点击:

org.mockito.exceptions.misusing.MissingMethodInvocationException

javamockitojunit4

提问by user3123690

I am getting following exceptions when I run Junit test.

运行 Junit 测试时出现以下异常。

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 cannotbe stubbed/verified.
  2. inside when() you don't call method on mock but on some other object.
  3. the parent of the mocked class is not public. It is a limitation of the mock engine.

org.mockito.exceptions.misusing.MissingMethodInvocationException:

when() 需要一个参数,该参数必须是“对模拟的方法调用”。例如:

   when(mock.getArticles()).thenReturn(articles);

此外,出现此错误的原因可能是:

  1. 你存根:final/private/equals()/hashCode() 方法。这些方法不能被存根/验证。
  2. 在 when() 中,您不会在模拟上调用方法,而是在其他对象上调用方法。
  3. 模拟类的父类不是公开的。这是模拟引擎的限制。

Following is my code and the exception was thrown at the second when statement. I don't think that my test code didn't violate what the exception claims. I spent for a while, but couldn't figure out. Could someone help? What I need to test is getPermProducts method. In the getPermProducts method, I want to ignore isTempProduct method. So, when p1 came, I want it returns false, and when p2 came, I want it returns true etc..

以下是我的代码,在第二个 when 语句中抛出了异常。我不认为我的测试代码没有违反异常声明的内容。我花了一段时间,但无法弄清楚。有人可以帮忙吗?我需要测试的是 getPermProducts 方法。在 getPermProducts 方法中,我想忽略 isTempProduct 方法。因此,当 p1 来时,我希望它返回 false,而当 p2 来时,我希望它返回 true 等等。

@Named(ProductManager.NAME)
public class ProductManager {

    @Resource(name = ProductService.NAME)
    private ProductService productService;

    public List<Product> getPermProducts(Set<Product> products) {
        Iterator<Product> it = products.iterator();
        List<Product> cProducts = new ArrayList<Product>();
        Product p;
        while (it.hasNext()) {
            p = it.next();
            if (!isTempProduct(p)) {
            cProducts.add(p);
            }
        }
        return cProducts;
    }

    public Boolean isTempProduct(Product product) {
    if (product instanceof PermProduct) {
    return false;
    }
    Set<ProductItems> pItems = product.getProductItems();
        if (pItems.isEmpty()) {
        return false;
    }
    Iterator<ProductItem> itr = pItems.iterator();
    while (itr.hasNext()) {
        if (itr.next() instanceof TempItem) {
            return true;
        }
    }
    return false;
}

public Product getProduct(Integer productId) {
    Product p = productService.getProduct(productId);
    return p;
    }

}



@RunWith(MockitoJUnitRunner.class)
public class ProductManagerTest {


    @InjectMocks
    private ProductManager mockProductManager;
    @Mock
    private ProductService mockProductService;//not being used here

    private static final Integer PRODUCT_ID_1 = 1;
    private static final Integer PRODUCT_ID_2 = 2;

    @Test
    public void getProduct(){
        Product p1 = mock(PermProduct.class);
            p1.setProductId(PRODUCT_ID_1);
        when(mockProductManager.getProductId()).thenReturn(PRODUCT_ID_1);
        when(mockProductManager.isTempProduct(p1)).thenReturn(false);
            Product p2 = mock(TempProduct.class);
            p2.setProductId(PRODUCT_ID_2);
            when(mockProductManager.isTempProduct(p2)).thenReturn(true);
            List<Product> products = Mock(List.class);
            products.add(p1);
            products.add(p2);
            Iterator<Product> pIterator = mock(Iterator.class);
            when(prodcuts.iterator()).thenReturn(pIterator);
            when(pIterator.hasNext()).thenReturn(true, true, false);
    when(pIterator.next()).thenReturn(p1, p2);
            asserEquals(1, mockProductManager.getPermProducts(products).size());

    }

}

SOLUTION: I updated my test based on enterbios's answer. I used partial mocking, but as enterbios suggested, we should avoid it, but sometimes we need it. I found that we can have both non-mocked and partial mocked class same time.

解决方案:我根据 enterbios 的回答更新了我的测试。我使用了部分模拟,但正如 enterbios 建议的那样,我们应该避免它,但有时我们需要它。我发现我们可以同时拥有非模拟类和部分模拟类。

@RunWith(MockitoJUnitRunner.class)
public class ProductManagerTest {

    @InjectMocks
    private ProductManager productManager;//not being used here
    @Mock
    private ProductService mockProductService;//not being used here

    @Spy
    private OtherService other = new OtherService();//not being used here

    @InjectMocks
    final ProductManager partiallyMockedProductManager = spy(new ProductManager());

    private static final Integer PRODUCT_ID_1 = 1;
    private static final Integer PRODUCT_ID_2 = 2;

    @Test
    public void getProduct() {
        Product p1 = new PermProduct();
        p1.setProductId(PRODUCT_ID_1);
        Product p2 = new Product();
        p2.setProductId(PRODUCT_ID_2);
        List<Product> products = new ArrayList<Product>();
        products.add(p1);
        products.add(p2);

        doReturn(false).when(partiallyMockedProductManager).isTempProduct(p1);
        doReturn(true).when(partiallyMockedProductManager).isTempProduct(p2);
        assertEquals(1, partiallyMockedProductManager.getPermProducts(products).size());
        verify(partiallyMockedProductManager).isTempProduct(p1);
        verify(partiallyMockedProductManager).isTempProduct(p2);
    }
}

采纳答案by enterbios

Your mockProductManager is actually not a mock but an instance of ProductManager class. You shouldn't mock a tested object. The way to mock some methods from tested object is using a spy but I recommend you to not use them, or even to not think about them unless you're fighting with some ugly legacy code. I think your second 'when' should be replaced with assertion, like:

您的 mockProductManager 实际上不是模拟,而是 ProductManager 类的实例。你不应该模拟一个被测试的对象。从测试对象模拟某些方法的方法是使用间谍,但我建议您不要使用它们,甚至不要考虑它们,除非您正在与一些丑陋的遗留代码作斗争。我认为您的第二个“何时”应该用断言代替,例如:

assertFalse(mockProductManager.isTempProduct(p1));

because what you really want to check in this test is if productManager.isTempProduct(p1) returns false for all instances of PermProduct. To verify results of some method calls/objects states you should use assertions. To make your life with assertions easier you can take a look on some helpful libraries like Hamcrest or FEST (http://docs.codehaus.org/display/FEST/Fluent+Assertions+Module). FEST is simpler for beginners I think.

因为在此测试中您真正想要检查的是 productManager.isTempProduct(p1) 是否为 PermProduct 的所有实例返回 false。要验证某些方法调用/对象状态的结果,您应该使用断言。为了让断言更轻松,您可以查看一些有用的库,例如 Hamcrest 或 FEST ( http://docs.codehaus.org/display/FEST/Fluent+Assertions+Module)。我认为 FEST 对于初学者来说更简单。