Org. Mockito. Exceptions. Misusing. Missingmethodinvocationexception

I am getting following exceptions when I run Junit test.

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.
  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.

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..

@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.

@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);
    }
}

1 Answer

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:

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 (). FEST is simpler for beginners I think.

5

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Maya Lin-Takahashi

Maya Lin-Takahashi

Consumer Tech & Gadget Reviewer

Maya is a hardware enthusiast who tests and reviews smart home devices, smartphones, wearables, and audio gear. She focuses on practical consumer value and build quality.

Share this article
Twitter Facebook Pinterest