为什么使用 Spring Boot 时,test 中的 JSON 序列化与 main 中的不同?

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

我注意到开箱即用的 JSON 序列化在生产和单元测试中的工作方式不同。当我使用

./gradlew bootRun
运行应用程序时,一切正常的事情在单元测试中失败了。我想了解为什么会这样,以及如何使事情在两个地方都以相同的方式工作,而不必编写自定义配置只是为了使测试模拟生产。

为了重现,我使用使用 Spring Initializr 创建的 Java 17 在 Spring Boot 3.1.2 中创建了一个简单的 HelloWorld API 服务器。我正在使用 Lombok 和 Guava (以及 WebFlux,这对于这个问题可能并不重要)。

我有一个这样定义的 API:

import lombok.*;
import com.google.common.collect.*;

@Builder
@Value
public class SearchResult {
  @Singular
  ImmutableList<String> results;
}

@RestController
@RequestMapping("/api/v1/search")
final class SearchController {
  @GetMapping(produces = "application/json")
  public Mono<SearchResult> search() {
    return Mono.just(SearchResult.builder().result("result1").result("result2").build());
  }
}

当我运行

./gradlew bootRun
时,效果非常好。然而,当我尝试测试这个时,事情变得很奇怪。我的测试看起来像这样:

@AutoConfigureWebTestClient
@SpringBootTest
final class SearchControllerTest {
  @Autowired private WebTestClient webTestClient;

  @Test
  public void search() {
    var response = webTestClient.get()
      .uri("/api/v1/search")
      .header("Content-Type", "application/json")
      .exchange();

    response.expectStatus().isOk();
    response.expectBody(SearchResult.class).isEqualTo(...);
  }
}

有两件事会导致此测试失败。首先,如果我将

ImmutableList
更改为
java.util.List
,一个模糊的错误就会消失。第二个问题是它说如果没有默认构造函数就无法反序列化对象。

我可以通过删除

@Value
并将其设为 Java
record
(因为我希望该对象是不可变的)并仅在我的单元测试中创建一个自定义对象映射器来完成这项工作,这样显式注册
GuavaModule
:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.guava.GuavaModule;

@Configuration
public class TestConfig {
  @Bean
  public ObjectMapper objectMapper() {
    var mapper = new ObjectMapper();
    mapper.registerModule(new GuavaModule());
    return mapper;
  }
}

但我不想做任何这些事情。我希望能够让我的测试使用已经注入到我的主要生产代码中的任何 ObjectMapper。这将使我的测试更加真实,并让我使用我显然已经能够在正常应用程序中使用的功能。我也很好奇为什么/如何在测试中使用不同的东西。

java spring-boot guava lombok
1个回答
0
投票

当您启动应用程序并在自己的应用程序中调用端点时,我怀疑您会遇到相同的错误?

您可以向 SearchResult 类添加默认构造函数,例如 lombok NoArgsConstructor、AllArgsConstructor 和/或RequiredArgsConstructor。

这应该可以解决您的反序列化问题。

© www.soinside.com 2019 - 2024. All rights reserved.