在春季集成测试中模拟 RestTemplateBuilder 和 RestTemplate

2022-09-04 20:34:04

我有一个REST资源,它注入了一个来构建一个:RestTemplateBuilderRestTemplate

public MyClass(final RestTemplateBuilder restTemplateBuilder) {
    this.restTemplate = restTemplateBuilder.build();
}

我想测试该类。我需要模拟对另一个服务的调用:RestTemplate

request = restTemplate.getForEntity(uri, String.class);

我在IT中尝试过这个:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MyIT {

@Autowired
private TestRestTemplate testRestTemplate;
@MockBean
private RestTemplateBuilder restTemplateBuilder;
@Mock
private RestTemplate restTemplate;

@Test
public void shouldntFail() throws IOException {

    ResponseEntity<String> responseEntity = new ResponseEntity<>(HttpStatus.NOT_FOUND);
    when(restTemplateBuilder.build()).thenReturn(restTemplate);
    when(restTemplate.getForEntity(any(URI.class), any(Class.class))).thenReturn(responseEntity);
...
ResponseEntity<String> response = testRestTemplate.postForEntity("/endpoint", request, String.class);
  ...
}
}

当我运行测试时,我得到以下异常:

java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.test.web.client.TestRestTemplate': Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: RestTemplate must not be null

如何正确执行此操作?


答案 1

你的问题是执行的顺序。在有机会在 .解决方案是在插入到上下文中时提供已完全设置的。你可以这样做。MockBean@TestRestTemplateBuilder

将以下内容添加到批注中。您的 Spring Boot 应用程序类在哪里。@SpringBootTestTestApplication

classes = {TestApplication.class, MyIT.ContextConfiguration.class},

从而修改您的类成员,删除您的 restTemplate 和 restTemplateBuilder。

@Autowired
private TestRestTemplate testRestTemplate;

向类中添加一个静态内部类:MyIT

@Configuration
static class ContextConfiguration {
  @Bean
  public RestTemplateBuilder restTemplateBuilder() {

    RestTemplateBuilder rtb = mock(RestTemplateBuilder.class);
    RestTemplate restTemplate = mock(RestTemplate.class);

    when(rtb.build()).thenReturn(restTemplate);
    return rtb;
  }
}

在测试中,修改模拟以执行任何操作:RestTemplate

@Test
public void someTest() {

  when(testRestTemplate.getRestTemplate().getForEntity(...
}

答案 2

我遇到了类似的问题。我的服务类在构造函数和私人领域,我想嘲笑。RestTemplateBuilderRestTemplateRestTemplate

我解决了在我的服务类Bean创建后使用Spring类更改我的私有字段RestTemplate的问题。ReflectionTestUtils

@Mock
private RestTemplate restTemplate;

@Autowired
private MyServiceClass myServiceClass;

@BeforeEach
void setUp() {
    ReflectionTestUtils.setField(myServiceClass, "restTemplate", restTemplate);
}

推荐