【问题标题】:If you want to use assertThrows while testing, should you do that with stubs or mocks?如果您想在测试时使用 assertThrows,您应该使用存根还是模拟?
【发布时间】:2023-04-10 19:23:01
【问题描述】:

当有人试图用值 0 调用它时,我有这个方法会抛出一个 IllegalArgumentException

我想为方法getFrequentRenterPoints 编写几个存根和模拟测试。

我不知道模拟中使用的任何“何时”或“验证”语句,所以我将模拟的部分和存根的部分混合在一起并想出了这个:

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

是否可以与其他 Mocks 一起上课,或者如果我想使用 assertThrows 是否应该将其更改为存根?或者我可以在模拟中使用assertThrows 吗?

【问题讨论】:

  • 我不知道是否推荐,因为它取决于原始代码。
  • 设置一个模拟抛出,如果它被调用,然后调用它有什么意义?您无需测试 mockito 是否有效。
  • @AndyTurner 老实说我不知道​​,我只是根据我们在课堂上做的例子来模拟我的测试用例。我认为这会在用 0 调用时抛出它,如果这有意义的话

标签: java mocking mockito stub


【解决方案1】:

answer from Benjamin Eckardt 是正确的。

但我尝试从另一个角度来解决这个问题:何时使用模拟?我是 one of my favourite answers 这个问题。

所以在实践中:

假设您的代码是这样的(只是猜测所有业务对象和名称...):

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

为此,您不需要也不应该在这里模拟任何东西。

但是当事情变得像你的方法变得更复杂时:

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

现在,如果您测试renterId >= 1,那么renterPointService 如何实例化它以不获取NPE?说如果它是注入的并且需要拉起沉重的框架进行测试,或者它需要非常繁重的构造等等?你没有,你嘲笑它。

您正在测试Movie 类而不是RenterPointService 类,因此您不必费心去思考RenterPointService 是如何工作的,而是在Movie 类中使用它时返回什么。 仍然:你没有模拟你正在测试的类Movie

假设您使用的是 Mockito 并使用注释,那么模拟将在您的测试类中完成,例如:

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

然后你会模拟 renterPointService 的方法,比如:

when(renterPointService.getRenterPoints(anyInt))
    .thenReturn(someListContaineingMockRenterPointsForThisTest);

【讨论】:

  • 非常感谢您的详细解答!
【解决方案2】:

通常您希望测试的生产方法抛出而不是模拟或存根。我是用new Movie()起草的。

此外,在这种情况下,将调用分成 whenthen 并没有什么意义,因为如果 movieMock.getFrequentRenterPoints(0); 抛出,assertThrows(...) 将永远不会被执行。

要将given/when/then 结构与assertThrows API 一起应用,您可以通过某种方式提取传递的lambda,但我个人认为它没有多大好处。

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

    // when/then
    assertThrows(IllegalArgumentException.class, () -> {
        movieMock.getFrequentRenterPoints(0);
    });
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-19
    • 2010-11-23
    • 1970-01-01
    • 2021-12-24
    • 1970-01-01
    相关资源
    最近更新 更多