模拟 RestTemplate 调用返回 HTTP 500

问题描述 投票:0回答:1

我的 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>。

java spring-boot mockito rest-assured
1个回答
0
投票

您应该使用 @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\"]"));
}
}
© www.soinside.com 2019 - 2024. All rights reserved.