1

I have this Method that throws an IllegalArgumentException when somebody tries to call it with value 0.

I want to write several stub and mock tests - for example - for the method getFrequentRenterPoints.

I coudn't figure out any "when" or "verify" statements which are used in mocks so I mixed parts of mocks and parts of stubs together and came up with this:

@Test
public void methodGetFrequentRenterPointsShouldThrowIllegalArgumentException() {
    //given
    Movie movieMock = mock(Movie.class);
    //when
    movieMock.getFrequentRenterPoints(0);
    //then
    assertThrows(IllegalArgumentException.class, () -> {
        movieMock.getFrequentRenterPoints(0);
    });
}

Is it okay to have in a class with other Mocks, or if I want to use assertThrows should I change this into a stub? Or can I use assertThrows with mocks?

pirho
  • 11,565
  • 12
  • 43
  • 70
tryingtoflow
  • 61
  • 1
  • 6
  • I can't know if it's recommended or not because it depends on the original code. – Adrian Lagartera Jun 23 '20 at 15:56
  • What's the point in setting up a mock to throw if it's called, and then calling it? You don't need to test that mockito works. – Andy Turner Jun 23 '20 at 16:08
  • @AndyTurner To be honest I have no idea, I am just modeling my test cases off of examples we did during class. I thaught this would throw it when it's called with a 0, if that makes sense – tryingtoflow Jun 23 '20 at 16:19

2 Answers2

2

The answer from Benjamin Eckardt is correct.

But I try to approach this question from another point of view: when to use mocking? This is one of my favourite answers to that question.

So in practise:

Say your code is like (just guessing all the business objects & names...):

List<RenterPoints> getFrequentRenterPoints(int renterId) {
    if(p <= 0) {
        throw new IllegalArgumentException();
    }
    // this is just the rest of code in which your test does not enter because 
    // of thrown exception
    return somethingToReturn();
}

For this you do not need and you should not want to mock anything here.

But when things get more complicated like your method would be like:

List<RenterPoints> getFrequentRenterPoints(int renterId) {
    if(p <= 0) {
        throw new IllegalArgumentException();
    }
    // What is this?
    // It is injected in the Movie - say - like
    //
    // @Resource
    // private RenterPointService renterPointService;
    List<RenterPoints> unfiltered = renterPointService.getRenterPoints(renterId);
    return filterToFrequent(unfiltered);
}

Now if you test renterId >= 1 what about this renterPointService how do you instantiate it to not get NPE? Say if it is injected and requires to pull up heavy framework for testing or it requires very heavy construction or so? You do not, you mock it.

You are testing the class Movie not the class RenterPointService so you should not bother to think how RenterPointService works but what it returns when used in the class Movie. Still: you do not mock the class Movie which you are testing.

Assuming using you are using Mockito and using annotations the mocking would be then done in your test class like:

@Mock
private RenterPointService renterPointService;
@InjectMocks
private Movie movie;

Then you would do mocking of methods for renterPointService like:

when(renterPointService.getRenterPoints(anyInt))
    .thenReturn(someListContaineingMockRenterPointsForThisTest);
pirho
  • 11,565
  • 12
  • 43
  • 70
1

Usually you expect the tested production method to throw and not the mock or stub. I drafted it by using new Movie().

Furthermore in that case it does not really make sense to separate the calls into when and then because if movieMock.getFrequentRenterPoints(0); throws, assertThrows(...) will never be executed.

To apply the given/when/then structure with the assertThrows API you could extract the passed lambda in some way, but I personally don't see much benefit in it.

@Test
public void methodGetFrequentRenterPointsShouldThrowIllegalArgumentException() {
    // given
    Movie movieMock = new Movie();

    // when/then
    assertThrows(IllegalArgumentException.class, () -> {
        movieMock.getFrequentRenterPoints(0);
    });
}
Benjamin Eckardt
  • 709
  • 6
  • 10