在 Spring 中 Mock RestTemplate

简介: 本文介绍了两种在单元测试中 mock RestTemplate 调用的方法,避免真实 HTTP API 调用以提高测试可控性。一是使用 Mockito 模拟库,通过 @Mock 和 when/then 方法定义模拟行为;二是借助 Spring Test 提供的 MockRestServiceServer,创建模拟服务器定义请求响应交互。文中结合具体代码示例展示了两种方法的实现细节,并强调了 RestTemplate 实例的一致性配置。适用于需要模拟外部 HTTP 调用的集成测试场景。

如果我们程序中使用了 RestTemplate 进行 HTTP API 调用。通常在编写单元测试时,为了让测试可控,会将 RestTemlate 调用进行 mock,而不是进行真实的 HTTP API 调用。

这里,我们将介绍两种 mock RestTemplate 调用的方法。一个是比较流行的 Mockito 模拟库,另一个是使用 Spring Test 提供的 MockRestServiceServer 模拟服务器,它可以创建模拟服务器以定义服务器交互。

使用 Mockito 模拟

使用 Mockito 模拟 RestTemplate 测试我们的服务将像其他任何涉及模拟的测试一样简单,下面我们就来看看怎么使用吧。

下面这段代码描述的是,一个 UserService 类,该类通过 HTTP 请求获取用户信息。

java

代码解读

复制代码

@Service("userServiceRest")
public class UserService {

    @Autowired
    private RestTemplate restTemplate;

    public List<UserVO> getUsers() {
        UserVO[] users = restTemplate.getForObject("http://localhost:8080/users", UserVO[].class);
        if (users == null) {
            return Collections.emptyList();
        }
        return Arrays.asList(users);
    }
}

现在,我们要为 UserService 类的 getUsers() 编写单元测试。测试代码如下:

java

代码解读

复制代码

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTest {
    
    // 模拟一个假的 RestTemplate 实例
    @Mock
    private RestTemplate restTemplate;

    @Autowired
    @Qualifier("userServiceRest")
    @InjectMocks
    private UserService userService;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testGetUsers() {
        UserVO mockUser = new UserVO(1, "mock-test");
        // 模拟一个假的请求
        Mockito.when(restTemplate.getForObject("http://localhost:8080/users", UserVO[].class))
                .thenReturn(new UserVO[]{mockUser});
        List<UserVO> users = userService.getUsers();
        Assert.assertFalse(CollectionUtils.isEmpty(users));
        Assert.assertEquals(1, users.size());
        UserVO userVO = users.get(0);
        Assert.assertEquals(mockUser.getId(), userVO.getId());
        Assert.assertEquals(mockUser.getName(), userVO.getName());
    }
}

上面的单元测试中,我们首先使用 Mockito 模拟库中 @Mock 注解创建一个假 RestTemplate 实例。

然后,我们使用 @InjectMocks 注释了 UserService 实例,以将模拟的实例注入到其中。

最后,在测试方法中,我们使用 Mockito 的 when() 和 then() 方法定义了模拟的行为。

使用 Spring Test 模拟

Spring Test 模块中包含一个叫 MockRestServiceServer 的模拟服务器。通过这种方法,我们将服务器配置为在通过 RestTemplate 实例调度特定请求时返回特定对象。最后,我们可以在该服务器实例上调用 verify() 方法验证是否满足所有期望。

MockRestServiceServer 实际上是通过使用 MockClientHttpRequestFactory 拦截 HTTP API 调用来工作的。根据我们的配置,它会创建预期请求和相应的响应列表。当 RestTemplate 实例调用 API 时,它将在期望列表中查找请求并返回相应的响应。因此,它无需在任何其他端口上运行 HTTP 服务器来发送模拟响应。

下面,我们使用 MockRestServiceServer 为 UserService 类的 getUsers() 编写单元测试,代码如下:

java

代码解读

复制代码

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceMockRestServiceServerTest {

    @Autowired
    private UserService userService;

    @Autowired
    private RestTemplate restTemplate;

    private MockRestServiceServer mockServer;

    private ObjectMapper mapper = new ObjectMapper();

    @Before
    public void init() {
        mockServer = MockRestServiceServer.createServer(restTemplate);
    }

    @Test
    public void testGetUsers() throws Exception {
        UserVO mockUser = new UserVO(1, "mock-test");
        // 模拟 RestTemplate 请求
        mockServer.expect(ExpectedCount.once(),
                MockRestRequestMatchers.requestTo(new URI("http://localhost:8080/users")))
                .andExpect(MockRestRequestMatchers.method(HttpMethod.GET))
                .andRespond(MockRestResponseCreators.withStatus(HttpStatus.OK)
                        .contentType(MediaType.APPLICATION_JSON)
                        .body(mapper.writeValueAsString(new UserVO[]{mockUser}))
                );
        List<UserVO> users = userService.getUsers();
        Assert.assertFalse(CollectionUtils.isEmpty(users));
        UserVO userVO = users.get(0);
        Assert.assertEquals(mockUser.getId(), userVO.getId());
        Assert.assertEquals(mockUser.getName(), userVO.getName());
        mockServer.verify();
    }

}

上面代码段中,我们使用 MockRestRequestMatchers 和 MockRestResponseCreators 中的静态方法以清晰易读的方式定义 REST 调用的期望和响应:

java

代码解读

复制代码

MockRestRequestMatchers.requestTo(new URI("http://localhost:8080/users"));

MockRestRequestMatchers.method(HttpMethod.GET);

MockRestResponseCreators.withStatus(HttpStatus.OK)
                        .contentType(MediaType.APPLICATION_JSON)
                        .body(mapper.writeValueAsString(new UserVO[]{mockUser});

这里需要提醒大家的是,测试类中的 RestTemplate 应该与 UserService 类中使用的实例相同。为了确保这一点,我们需要在 spring 容器中定义 RestTemplate bean,并在测试和实现中自动连接实例。

java

代码解读

复制代码

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

当我们编写集成测试并且只需要模拟外部 HTTP 调用时,使用 MockRestServiceServer 非常有用。


转载来源:https://juejin.cn/post/6911287412270301191

相关文章
|
11月前
|
XML 编解码 Java
Spring Boot 中的 RestTemplate和Retrofit 插件很好
Spring Boot 中的 RestTemplate和Retrofit 插件很好
235 1
|
11月前
|
XML 编解码 Java
我为什么放弃Spring Boot 中的 RestTemplate?选择 Retrofit
我为什么放弃Spring Boot 中的 RestTemplate?选择 Retrofit
168 0
|
11月前
|
Java Spring
【编程笔记】在 Spring 项目中使用 RestTemplate 发送网络请求
【编程笔记】在 Spring 项目中使用 RestTemplate 发送网络请求
158 0
|
11月前
|
Java
SpringBoot集成RestTemplate组件
SpringBoot集成RestTemplate组件
127 0
|
6月前
|
Java 测试技术 开发者
必学!Spring Boot 单元测试、Mock 与 TestContainer 的高效使用技巧
【10月更文挑战第18天】 在现代软件开发中,单元测试是保证代码质量的重要手段。Spring Boot提供了强大的测试支持,使得编写和运行测试变得更加简单和高效。本文将深入探讨Spring Boot的单元测试、Mock技术以及TestContainer的高效使用技巧,帮助开发者提升测试效率和代码质量。
633 2
|
9月前
|
Java Spring
spring restTemplate 进行http请求的工具类封装
spring restTemplate 进行http请求的工具类封装
328 3
|
9月前
|
文字识别 Java Python
文本,文识10,springBoot提供RestTemplate以调用Flask OCR接口,调用flask实现ocr接口,用paddleocr进行图片识别云服务技术,单个paddleocr接口有影响
文本,文识10,springBoot提供RestTemplate以调用Flask OCR接口,调用flask实现ocr接口,用paddleocr进行图片识别云服务技术,单个paddleocr接口有影响
|
9月前
|
Java 微服务 Spring
微服务04---服务远程调用,根据订单id查询订单功能,根据id查询订单的同时,把订单所属的用户信息一起返回,Spring提供了一个工具RestTemplate,Bean写在对象前面,以后可以在任何地
微服务04---服务远程调用,根据订单id查询订单功能,根据id查询订单的同时,把订单所属的用户信息一起返回,Spring提供了一个工具RestTemplate,Bean写在对象前面,以后可以在任何地
|
10月前
|
Java Spring
springboot使用RestTemplate(基于2.6.7,返回泛型)
springboot使用RestTemplate(基于2.6.7,返回泛型)
153 0
|
缓存 Java 数据库
【Spring Cloud系列】- RestTemplate使用详解(下)
【Spring Cloud系列】- RestTemplate使用详解(下)
616 0
下一篇
oss创建bucket