1. 概述

在Java中模拟方法时,根据传入参数返回不同的响应可能是有用的。本文将探讨根据需求复杂性实现这一目标的不同方法。

2. 设置

首先,让我们创建一个想要模拟的服务示例:

class ExampleService {
    int getValue(int arg){
        return 1;
    }
}

我们有一个非常简单的服务,只有一个方法。该方法接受一个整数作为参数,并返回一个整数。请注意,参数和返回值之间没有关联,因此默认情况下,它总是返回1。

3. 连续模拟的局限性

让我们来看看连续模拟,以及我们可以做什么和不能做什么。我们可以使用连续模拟,按照我们提供的输入顺序从我们的模拟中获取不同的参数。这显然缺乏对特定输入匹配期望输出的控制,但在许多情况下很有用。要做到这一点,我们将要模拟的方法传递给when()。然后,我们链式调用*thenReturn()*,按照我们想要的顺序提供响应:

@Test
void givenAMethod_whenUsingConsecutiveStubbing_thenExpectResultsInOrder(){
    when(exampleService.getValue(anyInt())).thenReturn(9, 18, 27);
    assertEquals(9, exampleService.getValue(1));
    assertEquals(18, exampleService.getValue(1));
    assertEquals(27, exampleService.getValue(1));
    assertEquals(27, exampleService.getValue(1));
}

从断言中可以看出,尽管始终传入1作为参数,但我们按照预期顺序接收了正确的值。一旦所有值都返回后,所有后续调用将返回最终值,如测试中的第四个调用所示。

4. 为不同参数模拟调用

*我们可以扩展对when()thenReturn()的使用,为不同的参数返回不同的值:*

@Test
void givenAMethod_whenStubbingForMultipleArguments_thenExpectDifferentResults() {
    when(exampleService.getValue(10)).thenReturn(100);
    when(exampleService.getValue(20)).thenReturn(200);
    when(exampleService.getValue(30)).thenReturn(300);

    assertEquals(100, exampleService.getValue(10));
    assertEquals(200, exampleService.getValue(20));
    assertEquals(300, exampleService.getValue(30));
}

在*when()中的参数是我们想要模拟的方法,以及我们想要指定响应的值。通过将when()的调用与thenReturn()*链接,我们指示模拟器在接收到正确参数时返回请求的值。我们可以自由地在模拟器上应用这些规则以处理一系列输入。只要提供预期的输入值,我们就会收到请求的返回值。

5. 使用 thenAnswer()

更复杂的选项是使用thenAnswer(),它提供了最大的控制。这允许我们获取参数,对其进行任何所需的计算,然后在与模拟器交互时返回一个值:

@Test
void givenAMethod_whenUsingThenAnswer_thenExpectDifferentResults() {
    when(exampleService.getValue(anyInt())).thenAnswer(invocation -> {
        int argument = (int) invocation.getArguments()[0];
        int result;
        switch (argument) {
        case 25:
            result = 125;
            break;
        case 50:
            result = 150;
            break;
        case 75:
            result = 175;
            break;
        default:
            result = 0;
        }
        return result;
    });
    assertEquals(125, exampleService.getValue(25));
    assertEquals(150, exampleService.getValue(50));
    assertEquals(175, exampleService.getValue(75));
}

在上面的例子中,我们使用提供的调用对象的getArguments()获取参数。这里假设我们有一个单一的整数参数,但我们可以处理不同类型。我们还可以检查是否有至少一个参数,并且将类型转换为整数成功。为了演示其功能,我们使用了一个switch语句根据输入返回不同的值。底部的断言显示,我们的模拟服务返回了switch语句的结果。

这个选项允许我们在单个*when()*调用中处理无限数量的输入。牺牲的是测试的可读性和维护性。

6. 总结

在这篇教程中,我们看到了配置模拟方法以返回不同值的三种方式。我们研究了连续模拟,发现它对于任何输入返回已知值并且非常有用,但除此之外的限制很大。使用*when()thenReturn()结合处理每个可能的输入提供了一种简单且控制更好的解决方案。或者,我们可以使用thenAnswer()*以最大限度地控制给定输入和期望输出之间的关系。根据测试的需求,所有三种方法都有其用处。

如往常一样,示例代码的完整版本可以在GitHub上找到。