A.Mahmoud
A.Mahmoud

Reputation: 65

spying an array element with mockito returns wanted but not invoked when the method is invoked

**UPDATE : I have misunderstood the way spys function completely, I should be calling the spy version of a method in order for it to be verified NOT the real object method Ex : r.getPrice(); then verify(r).getPrice(); I still haven't figured the right way to get what i want but i thought i have to ask if i should delete this question ?

I'm spying an array element like this

@Test
public void testMakeCoffee_1() {
    Recipe r = spy(stubRecipies[0]);

    assertEquals(25,coffeeMaker.makeCoffee(0, 75)); // first index

            verify(r).getPrice();
});

this is the implementation of the makeCoffee method

public synchronized int makeCoffee(int recipeToPurchase, int amtPaid) {
    int change = 0;

    if (getRecipes()[recipeToPurchase] == null) {
        change = amtPaid;
    } else if (getRecipes()[recipeToPurchase].getPrice() <= amtPaid) {
        if (inventory.useIngredients(getRecipes()[recipeToPurchase])) {
            change = amtPaid - getRecipes()[recipeToPurchase].getPrice();
        } else {
            change = amtPaid;
        }
    } else {
        change = amtPaid;
    }

    return change;
}

getRecipes() implementation inside CoffeeMaker class

public synchronized Recipe[] getRecipes() {
    return recipeBook.getRecipes();
}

RecipeBook is a mocked class, stubRecipies is an array that contains my custom recipes to test and getRecipes() of the RecipeBook class is stubbed like this

recipeBookStub = mock(RecipeBook.class);
stubRecipies = new Recipe [] {recipe1, recipe2, recipe3};
when(recipeBookStub.getRecipes()).thenReturn(stubRecipies);

getRecipes() should return the list of recipes, hence replacing it with my array of recipes stubRecipies.

however when i call verify method of mockito on the getPrice() method of the spy object stubRecipies[0] i get a 'wanted but not invoked error' how is it possible that the method is not invoked, knowing that the usage above returns the correct value.

** edit : i tried manually calling recipe1.getPrice() and still i got 'wanted but not invoked error' , but when i called r.getPrice() the test passed which is weird because i thought a spy object is supposed to capture the interactions with the real object.

Upvotes: 1

Views: 856

Answers (1)

MartinByers
MartinByers

Reputation: 1240

So from looking at your question and the comments, there are a few things I would recommend to take this forward.

So without seeing the entire code, I can not 100% sure if this is returning the expected Recipe[]

public synchronized Recipe[] getRecipes() {
    return recipeBook.getRecipes();
}

You should be injecting your mocked recipeBookStub into your CoffeeMaker.

Typically when writing code in a TDD style we start with the most basic case in this case I would try out the method until oyu can get your method passing:

public int makeCoffee(int recipeToPurchase, int amtPaid) { 
   getRecipes()[recipeToPurchase]getPrice();
   return 25;
}

Another good practice thing is to use as little logic in your test as possible.

rather the:

Recipe r = spy(stubRecipies[0]);

try:

Recipe r = spy(recipe1);

More significantly, the spied object is not being used in CoffeeMaker:

Recipe r = spy(stubRecipies[0]);

r is the mock, and is not the same object as in your array, you can quickly prove this with:

Assert.assertEquals(stubRecipies[0], r);
Assert.assertTrue(stubRecipies[0]== r);

the assertTrue will fail, meaning that stubRecipies[0] is not the same object as the spy (r)

if you set the first index in the array to equal your spied object you might find things work better

Upvotes: 1

Related Questions