簡體   English   中英

Spring 集成測試中的 Mocking RestTemplateBuilder 和 RestTemplate

[英]Mocking RestTemplateBuilder and RestTemplate in Spring integration test

我有一個 REST 資源,它注入了一個RestTemplateBuilder來構建一個RestTemplate

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

我想測試 class。 我需要模擬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

我該如何正確地做到這一點?

你的問題是執行順序。 在您有機會在您的@Test設置它之前,創建包含您的MockBean的上下文。 解決方案是提供一個RestTemplateBuilder ,它在插入上下文時就已經完全設置好了。 你可以這樣做。

將以下內容添加到您的@SpringBootTest注釋中。 其中TestApplication是您的 Spring Boot 應用程序類。

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(...
}

我有一個類似的問題。 我的服務RestTemplateBuilder在構造函數中有 RestTemplateBuilder 並將RestTemplate作為私有字段,我想模擬RestTemplate

我使用ReflectionTestUtils Spring class 解決了我的服務 class Bean 創建后更改我的私有字段 RestTemplate 的問題。

@Mock
private RestTemplate restTemplate;

@Autowired
private MyServiceClass myServiceClass;

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

只需使用反射來替換由構建器創建的 restTemplate 為模擬的 restTemplate。

例如:

@Mock
private RestTemplate mockRestTemplate;

@Test
public void shouldntFail() throws IOException {
    this.initRestTemplate()

    ResponseEntity<String> responseEntity = new ResponseEntity<>(HttpStatus.NOT_FOUND);
    when(mockRestTemplate.getForEntity(any(URI.class), any(Class.class))).thenReturn(responseEntity);
}

private void initRestTemplate() {
    Field field = ReflectionUtils.findField(MyClass.class, "restTemplate");
    if (ObjectUtils.isNotEmpty(field)) {
      field.setAccessible(Boolean.TRUE);
      ReflectionUtils.setField(field, *yourObjectWithRestRemplate*, mockRestTemplate);
    }
}

P.S. I used ReflectionUtils provided by Spring, you can use any you prefer.

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM