java理解@MockBean与“RestTemplate RestTemplate”的用法
在第二个测试中,当模拟的restTemplate
调用时,我看到的行为是NullPointerException。这就指出了重置模拟的一个问题。让我惊讶的是修复(使两个测试都通过了)
修改源代码
@MockBean private RestTemplate restTemplate;
到
@MockBean(reset = MockReset.NONE) private RestTemplate restTemplate;
解决了这个问题。这里有几个问题:
- 为什么MockBean的默认@MockBean行为没有重置。重置工作李>
- 我设置测试的方式是否有问题,导致默认模拟重置。重置失败了吗李>
- 测试配置类有问题吗李>
希望我已经提供了足够的背景来回答这个问题
我创建了一个简单的例子来说明我所看到的: 测试配置:
@Profile("test")
@Configuration
public class TestConfiguration {
@Bean
@Primary
public ObjectNode getWeatherService(RestTemplate restTemplate) {
return new WeatherServiceImpl(restTemplate);
}
}
测试:
@SpringBootTest
@ActiveProfiles("test")
@AutoConfigureMockMvc
class SamTest {
@Autowired private MockMvc mockMvc;
@MockBean private RestTemplate restTemplate;
/*
Works:
@MockBean(reset = MockReset.NONE) private RestTemplate restTemplate;
Fails:
@MockBean(reset = MockReset.BEFORE) private RestTemplate restTemplate;
@MockBean(reset = MockReset.AFTER) private RestTemplate restTemplate;
*/
@Test
public void testOne() throws Exception {
Mockito.when(restTemplate.getForEntity("http://some.weather.api", ObjectNode.class))
.thenReturn(new ResponseEntity("{\"weather\" : \"rainy\"}", HttpStatus.OK));
// Makes call to standard @RestController with a @GetMapping
// Call to external API is contained in @Service class.
// Currently controller just passes through the json from the underlying service call.
this.mockMvc.perform(
get("/weather/check").
contentType(MediaType.APPLICATION_JSON_VALUE)).
andExpect(status().isOk());
}
@Test
public void testTwo() throws Exception {
Mockito.when(restTemplate.getForEntity("http://some.weather.api", ObjectNode.class))
.thenReturn(new ResponseEntity("{\"error\" : \"bandwidth\"}", HttpStatus.BANDWIDTH_LIMIT_EXCEEDED));
this.mockMvc.perform(
get("/weather/check").
contentType(MediaType.APPLICATION_JSON_VALUE)).
andExpect(status().is5xxServerError());
}
}
该服务:
@Service
public class WeatherServiceImpl implements WeatherService {
private final RestTemplate restTemplate;
@Autowired
public WeatherServiceImpl(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@Override
public ObjectNode retrieve(URI uri) {
ResponseEntity<ObjectNode> response = restTemplate.getForEntity(uri, ObjectNode.class);
return response.getBody();
}
}
# 1 楼答案
对
@MockBean
默认行为存在误解:从^{} 方法文档中:
因此,在第一个测试用例执行后,您的
MockBean
将被重置并从应用程序上下文中注销,然后您的第二个测试用例将发现它为空,而在@MockBean(reset = MockReset.NONE)
的情况下,它不会像您所做的那样发生