2. 使用Mockito
我们可以使用Mockito完全模拟RestTemplate
的行为。在这种方法下,测试我们的服务就像进行其他涉及模拟的测试一样简单。
假设我们有一个简单的EmployeeService
类,它通过HTTP获取员工详细信息:
@Service
public class EmployeeService {
@Autowired
private RestTemplate restTemplate;
public Employee getEmployee(String id) {
ResponseEntity resp =
restTemplate.getForEntity("http://localhost:8080/employee/" + id, Employee.class);
return resp.getStatusCode() == HttpStatus.OK ? resp.getBody() : null;
}
}
现在让我们为之前的代码实现测试:
@ExtendWith(MockitoExtension.class)
public class EmployeeServiceTest {
@Mock
private RestTemplate restTemplate;
@InjectMocks
private EmployeeService empService = new EmployeeService();
@Test
public void givenMockingIsDoneByMockito_whenGetIsCalled_shouldReturnMockedObject() {
Employee emp = new Employee(“E001”, "Eric Simmons");
Mockito
.when(restTemplate.getForEntity(
"http://localhost:8080/employee/E001", Employee.class))
.thenReturn(new ResponseEntity(emp, HttpStatus.OK));
Employee employee = empService.getEmployee(id);
Assertions.assertEquals(emp, employee);
}
}
在上述JUnit测试类中,我们首先使用@Mock
注解让Mockito创建一个空的RestTemplate
实例。
然后,我们使用@InjectMocks
注解将这个空实例注入到EmployeeService
实例中。
最后,在测试方法中,我们使用Mockito的when/then支持定义了模拟对象的行为。
3. 使用Spring Test
Spring Test模块包含一个名为MockRestServiceServer
的模拟服务器。通过这种方法,我们可以配置服务器,使其在我们的RestTemplate
实例发送特定请求时返回特定的对象。此外,我们还可以在该服务器实例上进行verify()
操作,检查所有期望是否已满足。
MockRestServiceServer
实际上是通过使用MockClientHttpRequestFactory
拦截HTTP API调用来工作的。根据我们的配置,它会创建预期请求和响应的列表。当RestTemplate
实例调用API时,它会在自己的期望列表中查找请求,并返回相应的响应。
因此,它消除了在其他端口运行HTTP服务器以发送模拟响应的需要。
让我们使用MockRestServiceServer
为相同的getEmployee()
示例编写一个简单的测试:
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = SpringTestConfig.class)
public class EmployeeServiceMockRestServiceServerUnitTest {
@Autowired
private EmployeeService empService;
@Autowired
private RestTemplate restTemplate;
private MockRestServiceServer mockServer;
private ObjectMapper mapper = new ObjectMapper();
@BeforeEach
public void init() {
mockServer = MockRestServiceServer.createServer(restTemplate);
}
@Test
public void givenMockingIsDoneByMockRestServiceServer_whenGetIsCalled_thenReturnsMockedObject()() {
Employee emp = new Employee("E001", "Eric Simmons");
mockServer.expect(ExpectedCount.once(),
requestTo(new URI("http://localhost:8080/employee/E001")))
.andExpect(method(HttpMethod.GET))
.andRespond(withStatus(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON)
.body(mapper.writeValueAsString(emp))
);
Employee employee = empService.getEmployee(id);
mockServer.verify();
Assertions.assertEquals(emp, employee);
}
}
在前一段代码中,我们使用了MockRestRequestMatchers
和MockRestResponseCreators
的静态方法,以清晰、可读的方式定义REST调用的期望和响应:
import static org.springframework.test.web.client.match.MockRestRequestMatchers.*;
import static org.springframework.test.web.client.response.MockRestResponseCreators.*;
需要注意的是,测试类中的RestTemplate
应与EmployeeService
类中使用的同一个实例。为了确保这一点,我们在Spring配置中定义了一个RestTemplate
bean,并在测试和实现中自动注入:
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
当我们在编写集成测试并仅需要模拟外部HTTP调用时,使用MockRestServiceServer
非常有用。
4. 总结
在这篇简短的文章中,我们讨论了在编写单元测试时,通过HTTP模拟外部REST API调用的几种有效选项。
本文的源代码可以在GitHub上找到。