我的 Spring Boot 应用程序中有以下控制器类。
package com.tsdevelopment.springbootrest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.Arrays;
import java.util.List;
@RestController
public class SpringController {
private List<String> myList = Arrays.asList("Item 1", "Item 2");
@Autowired
RestTemplate restTemplate;
@GetMapping("/v1/resources")
public ResponseEntity<List<String>> getAllResources(@RequestParam(required = false) String parameter){
return ResponseEntity.ok(myList);
}
//API to API call
@GetMapping("/v1/resources/inter-api-call")
public ResponseEntity<List<String>> apiCall(){
List<String> apiResponse = restTemplate.getForEntity("http://localhost:8083/v1/resources", List.class).getBody();
return ResponseEntity.ok(apiResponse);
}
}
我正在尝试用以下课程来测试它:
package com.tsdevelopment.springbootrest;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import java.util.Arrays;
import java.util.List;
import org.hamcrest.Matchers;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SpringControllerTest {
@InjectMocks
SpringController springController;
@Mock
RestTemplate restTemplate;
@LocalServerPort
private int port;
@BeforeEach
public void setUp(){
RestAssured.port = port;
MockitoAnnotations.openMocks(this);
}
@Test
public void apiCall(){
Mockito.when(restTemplate.getForEntity("http://localhost:8083/v1/resources", List.class)).thenReturn(ResponseEntity.ok(Arrays.asList("Item 1", "Item 2")));
System.out.println("RestTemplate response: " + restTemplate.getForEntity("http://localhost:8083/v1/resources", List.class));
System.out.println("Controller response: " + springController.apiCall());
RestAssured.given()
.when()
.get("/v1/resources/inter-api-call")
.then()
.statusCode(200)
.body("", Matchers.equalTo("[\"Item 1\",\"Item 2\"]"));
}
}
当我执行测试时它失败了。我得到的日志是:
RestTemplate 响应:<200 OK OK,[Item 1, Item 2],[]> 控制器响应:<200 OK OK,[Item 1, Item 2],[]>
测试错误日志为:
java.lang.AssertionError:1 个期望失败。 预期状态代码 <200> 但实际是 <500>。
您应该使用 @MockBean,而不是在 RestTemplate 上使用 @Mock,这可确保 Spring Boot 在上下文中使用您的模拟。
当您使用@Mock时,您正在创建仅存在于测试类本身中的对象的模拟实例。该模拟对于 Spring 的依赖注入机制不可见,因此在实际测试执行期间,Spring 仍在其上下文中使用真正的 RestTemplate bean。
还要删除 @InjectMocks 注释,因为它是不必要的,因为您依赖于 Spring 的 @Autowired 依赖注入。
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SpringControllerTest {
@Autowired
SpringController springController;
@MockBean
RestTemplate restTemplate;
@LocalServerPort
private int port;
@BeforeEach
public void setUp(){
RestAssured.port = port;
}
@Test
public void apiCall(){
Mockito.when(restTemplate.getForEntity("http://localhost:8083/v1/resources", List.class))
.thenReturn(ResponseEntity.ok(Arrays.asList("Item 1", "Item 2")));
RestAssured.given()
.when()
.get("/v1/resources/inter-api-call")
.then()
.statusCode(200)
.body("", Matchers.equalTo("[\"Item 1\",\"Item 2\"]"));
}
}