有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java理解@MockBean与“RestTemplate RestTemplate”的用法

在第二个测试中,当模拟的restTemplate调用时,我看到的行为是NullPointerException。这就指出了重置模拟的一个问题。让我惊讶的是修复(使两个测试都通过了)

修改源代码 @MockBean private RestTemplate restTemplate;@MockBean(reset = MockReset.NONE) private RestTemplate restTemplate; 解决了这个问题。这里有几个问题:

  1. 为什么MockBean的默认@MockBean行为没有重置。重置工作
  2. 我设置测试的方式是否有问题,导致默认模拟重置。重置失败了吗
  3. 测试配置类有问题吗

希望我已经提供了足够的背景来回答这个问题

我创建了一个简单的例子来说明我所看到的: 测试配置:

@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) 个答案

  1. # 1 楼答案

    @MockBean默认行为存在误解:

    Why didn't the default @MockBean behavior of MockReset.RESET work? Is there something wrong with how I have set up my test such that default MockReset.RESET was failing?

    ^{}方法文档中:

    The reset mode to apply to the mock bean. The default is MockReset.AFTER meaning that mocks are automatically reset after each test method is invoked.

    因此,在第一个测试用例执行后,您的MockBean将被重置并从应用程序上下文中注销,然后您的第二个测试用例将发现它为空,而在@MockBean(reset = MockReset.NONE)的情况下,它不会像您所做的那样发生