0

I'm having problems with two void methods. In encouragedVenturesScoring I've followed this answer mocking an arraylist that will be looped in a for loop and haven't mocked the list, but passed a real list and added mocked objects.

Mockito gives me an InvalidUseOfMatchersException on this line

verify(effectList.get(Mockito.anyInt())).execute(playerHandler);

There are lots of questions on SO on this exception , and I think it's because of anyInt(). Anyway I changed it to

verify(effectList.get(0)).execute(playerHandler);

And now it's saying Wanted but not invoked effect.execute(playerHandler) Actually there were zero interactions with this mock

Is it because I put doNothing ? doNothing().when(effect).execute(playerHandler);


In my second method militaryStrengthScoring() method is there a way to skip the first chunk of code and just test the if..else condition? What would be the best approach to test this method?

Thank you for your time.

This is the class to be tested

 public class EndGameScoringBaseController implements EndGameScoringHandler {

private static final int[] TERRITORIES_REWARD = {0,0,1,4,10,20};
private static final int[] CHARACTERS_REWARD = {1,3,6,10,15,21};
private static final int RESOURCES_RATE = 5;
private static final int FIRST_MILITARY_REWARD = 5;
private static final int SECOND_MILITARY_REWARD = 2;

private PlayerHandler player;

public EndGameScoringBaseController(PlayerHandler player) {
    super();
    this.player = player;
}

@Override
public void encouragedVenturesScoring() {
    for (DevelopmentCard card : player.getPlayer().getPersonalBoard().getVentures()) {
        for (Effect e : card.getPermanentEffects())
            e.execute(player);
    }
}

@Override
public void militaryStrengthScoring(GameController game) {
    Set<Integer> points = new HashSet<>();
    int myPoints = this.player.getPointsHandler().getMilitaryPoints();

    for (PlayerHandler p: game.getPlayers()) {
        points.add(p.getPointsHandler().getMilitaryPoints());
    }
    int[] rank = new int[points.size()];
    int j = 0;
    for (Integer i : points) {
        rank[j] = i;
        j++;
    }

    Arrays.sort(rank);

    if (rank[rank.length-1] == myPoints) {
        player.getPointsHandler().winMilitaryPoints(FIRST_MILITARY_REWARD);
    }
    else if (rank[rank.length-2] == myPoints) {
        player.getPointsHandler().winVictoryPoints(SECOND_MILITARY_REWARD);
    }

}

Tested method for encouragedVenturesScoring

@Test
public void encouragedVenturesScoringTest() {
    //given
    List<DevelopmentCard> ventureList;
    ventureList = Arrays.asList(developmentCard, developmentCard);
    when(playerHandler.getPlayer().getPersonalBoard().getVentures()).thenReturn(ventureList);
    List<Effect> effectList;
    effectList = Arrays.asList(effect, effect);
    when(developmentCard.getPermanentEffects()).thenReturn(effectList);
    doNothing().when(effect).execute(playerHandler);

    //when
    endgameController.encouragedVenturesScoring();

    //then
    verify(effectList.get(Mockito.anyInt())).execute(playerHandler);
}

Incomplete tested method for militaryStrengthScoring

@Test
public void militaryStrengthScoringTest() {

//given     
when(playerHandler.getPointsHandler().getMilitaryPoints()).thenReturn(4);
doNothing().when(playerHandler.getPointsHandler()).winMilitaryPoints(FIRST_MILITARY_REWARD);

//when
endgameController.militaryStrengthScoring(gameController);

//then
/../    
}
GhostCat
  • 137,827
  • 25
  • 176
  • 248
LoSpazzino
  • 60
  • 1
  • 1
  • 7

2 Answers2

1

You can only verify mock objects created by Mockito.

But effectList is a "real" list. Therefore Mockito knows nothing about that object. Thus any attempt to verify that list must fail.

If you want to verify that object - then you have to mock it!

Of course, this means that you have specify all calls that will go to the mocked list.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • I'd also add if you are going into this level of mocking/effort your class is likely too complicated as it stands to effectively unit test and should be refactored asap. – Darren Forsythe Jul 06 '17 at 17:15
  • I don't think this is the problem, actually: `verify(effectList.get(0)).execute(playerHandler)` seems to be trying to verify _the Effect in the list, not the list itself_. I prefer not to allow extra method calls in my `when` and `verify` calls, but that's not really a problem. – Jeff Bowman Jul 06 '17 at 18:54
  • I was calling the wrong method and everything is fixed now with: `verify(effectList.get(0), times(4)).execute(playerHandler); verify(effectList.get(1), times(4)).execute(playerHandler);`. Could you suggest me the best way to refactor my second method `militaryStrengthScoringTest` so it's easier to test ? – LoSpazzino Jul 07 '17 at 07:59
  • Are you sure that this is really **verifying** anything? The fact that the method doesn't throw an error doesn't mean it is really doing anything. Have you ensured that your test is *failing* when something happens that the verification did not expect? – GhostCat Jul 07 '17 at 08:02
1

You're right that this is the problem:

verify(effectList.get(Mockito.anyInt())).execute(playerHandler);

Mockito only allows for calls like any() and anyInt() to stand in for parameters to the mock themselves, due to the internal implementation of matchers.

/*  OK */  when(yourMock.yourMethod(anyInt())).thenReturn(42);
/* BAD */  when(yourList.get(anyInt()).yourMethod(0)).thenReturn(42);

/*  OK */  verify(yourMock).yourMethod(anyInt());
/* BAD */  verify(yourList.get(anyInt())).yourMethod(0);

The failure with get(0) is likely an actual failure, and may be related to the fact that your encouragedVenturesScoringTest is actually not calling encouragedVenturesScoring, it's calling influencedCharactersScoring. If this continues to give you trouble after fixing that error, in ways related to Mockito, please edit your question.

Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251
  • Thank you! I completely missed I was calling the wrong method. I changed it to `endgameController.encouragedVenturesScoring()` and it's working now. Btw is this the best way to test methods like these? – LoSpazzino Jul 07 '17 at 07:56
  • @LoSpazzino Glad to help! For the "is this the best way to test", that could easily be a 20-page rant, so let me just say: I think unit tests are valuable and that this is a good start, but I'm concerned that overuse of mocks will make it really hard to determine whether your system actually works. Yes, you can verify that the call to `execute` succeeds, but I'd guess that your cards and players are relatively self-contained and easy to write (and test in isolation). Using them instead of Mockito simulations may make it easier to reason about whether your system actually works. – Jeff Bowman Jul 07 '17 at 08:09