java - 集成测试中 Spring Controller 中的 Mock Feign 客户端

标签 java unit-testing spring-boot mocking feign

我有一个使用内部不同服务的网关 Controller 。我尝试编写集成测试来模拟 Controller 的假客户端,但它没有按我的预期工作。

我有以下 Feign 客户端:

public interface StoreManagementClient {
    @RequestLine("GET /v1/stores/{storeId}")
    @Headers({"Accept: application/json", "Content-Type: application/json;charset=UTF-8"})
    StoreDetails getStoreDetails(@Param("storeId") String storeId);
}

商店 Controller :

@Validated
@Controller
@RequestMapping("${gateway.path}")
public class StoreController {

    @Autowired
    private StoreManagementClient storeManagementClient;

    @GetMapping(value = "/stores/{storeId}", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<StoreDetails> getStoreDetails(
            @PathVariable("storeId") String storeId) {
        StoreDetails details = storeManagementClient.getStoreDetails(storeId);
        return ResponseEntity.ok(details);
    }
}

以及集成测试:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {GatewayServiceApplication.class},
        webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class ClientIntegrationTest {
    @Autowired
    private StoreController storeController;

    @MockBean
    private StoreManagementClient storeManagementClient;

    private MockClient mockClient;

    @Before
    public void setUp() throws Exception {
        mockClient = new MockClient();
    }

    @Test
    public void testCorrectGetStoreDetailsRequest() throws JsonProcessingException {

        String storeId = "store-1";

        StoreDetails storeDetails = new StoreDetails();
        storeDetails.setId(storeId);
        storeDetails.setType("grocery");

        String response = new ObjectMapper().writeValueAsString(storeDetails);

        storeManagementClient = Feign.builder()
                .encoder(new JacksonEncoder())
                .decoder(new JacksonDecoder())
                .client(mockClient
                        .ok(RequestKey.builder(feign.mock.HttpMethod.GET, "/v1/stores/" + sroreId)
                                .headers(ImmutableMap.of(
                                        ACCEPT, newArrayList("application/json"),
                                        CONTENT_TYPE, newArrayList("application/json;charset=UTF-8"))).build(),
                                response
                        ))
                .target(new MockTarget<>(StoreManagementClient.class));

        // when
        ResponseEntity<StoreDetails> result = storeController.getStoreDetails(storeId);

        // then
        StoreDetails resultBody = result.getBody();

        assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
        assertThat(resultBody.getId()).isEqualTo(storeId);
        assertThat(resultBody.getType()).isEqualTo("grocery");
}

我认为测试应该根据描述的 Feign Client 模拟响应。但实际上它返回null

我应该在 mock Feign 客户端时做错什么吗?可能,我混合了一个测试 Feign 客户端和我自己的 Controller ,我需要将其分开并为 Feign 客户端编写单元测试,如 Mock Feign Client example ? 如果有任何建议,我将不胜感激

最佳答案

首先,用模拟替换 feign 客户端 StoreManagementClient:

@MockBean
private StoreManagementClient storeManagementClient;

然后在测试中您丢失了对模拟的引用并指向本地对象:

storeManagementClient = Feign.builder()....build();

但 Controller 仍然使用模拟

在纯java中,你可以做类似的事情:

Client client = new Client(null);
Controller controller = new Controller(client);
client = new Client(1);
assertThat(controller.get()).isEqualTo(1)) // no no no: is equal to null
PS。我希望将来我的回答是有建设性的

关于java - 集成测试中 Spring Controller 中的 Mock Feign 客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56358145/

相关文章:

java - Spring Boot 分页 - Mockito 存储库 findAll(Pageable) 返回 null

java - 从 Throwable 获取根错误消息

c# - 如何强制类为每个公共(public)方法获取单元测试?

php - 在 PHPUnit 中模拟时在回调中通过引用传递

maven-3 - Jboss EAP 上的 spring Boot 应用程序,servlet 上下文未加载

spring - 如何获取 thymeleaf 选择选项中的对象?

java - 如何使用 SilverTunnel-NG 在 Java 中建立 TOR 连接?

java - 最大数量的连续奇数等于一个目标

unit-testing - 使用适当的抽象时,我们是否需要对 GUI 进行单元测试?

java - Spring Boot - 使用 inMemoryAuthentication