Spring Boot单元测试中如何将对象序列化为application/hal+json?

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

在 Spring Boot 项目中,我尝试使用 HATEOAS 以 hal+json 格式序列化和反序列化相关对象。我正在使用

org.springframework.boot:spring-boot-starter-hateoas
来执行此操作,它在我的控制器中效果很好:

@GetMapping(path = "/{id}", produces = MediaTypes.HAL_JSON_VALUE + ";charset=UTF-8")
HttpEntity<Item> getItemById(@PathVariable Integer id) {
    Item item = itemRepository.findById(id).get();
    item.add(linkTo(ItemController.class).slash(item.getId()).withSelfRel());
    item.add(linkTo(methodOn(CategoryController.class).getCategoryById(item.getCategory().getId()))
        .withRel("category"));
    return new HttpEntity<>(item);
}

Item
类是:

@Entity
public class Item extends RepresentationModel<Item> {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "item_id")
    private Integer id;

    @ManyToOne
    @JoinColumn(name = "category_id", referencedColumnName = "category_id")
    @JsonIgnore
    private Category category;

    private String name;

    // Getters and Setters are present but not entered here in the question
}

调用 GET 方法将导致类似的结果

{
  "name": "foo"
  "_links": {
    "self": {
      "href": "http://localhost:8080/items/1"
    },
    "category": {
      "href": "http://localhost:8080/categories/2"
    }
  },
  "item_id": 1
}

这正是我想要的。

当我尝试为 POST 方法编写测试(旨在用于创建新的

Item
)时,现在出现了问题。这就是我的测试的样子:

@Test
void testCreate() throws Exception {
    Item testItem = new Item("test");
    testItem.add(Link.of("http://localhost:" + port + "/categories/2", "category"));

    // (objectMapper was @Autowire'd on class level)
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    ObjectWriter ow = objectMapper.writer().withDefaultPrettyPrinter();
    String itemSerialized = ow.writeValueAsString(testItem);

    mockMvc.perform(post("/items/")
        .content(itemSerialized)
        .contentType(MediaTypes.HAL_JSON_VALUE))
        .andExpect(status().isOK());
}

此序列化无法按需要工作,因为关系在

itemSerialized
字符串中如下所示:

  "links" : [{
    "rel" : "category",
    "href" : "http://localhost:61524/categories/2"
  }]

(正确的是带有下划线的

_links
和上面给出的
category
关系结构。)

据我了解,造成这种情况的原因是,我使用的

objectMapper
不知道需要序列化为json+hal格式。 (当控制器从
Item
返回
getItemById
时,默认/魔术会正确发生。)现在,确保测试中也发生正确序列化的正确方法是什么?

我读过有关使用

objectMapper.registerModule(new Jackson2HalModule());
的内容,这对我来说似乎很合理。但是我使用的时候却出现异常:

org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'org.springframework.hateoas.mediatype.hal.Jackson2HalModule$HalLinkListSerializer': 
Failed to instantiate [org.springframework.hateoas.mediatype.hal.Jackson2HalModule$HalLinkListSerializer]: 
No default constructor found

任何帮助将不胜感激!

java spring-boot unit-testing serialization spring-hateoas
1个回答
0
投票

在这种情况下,您必须与 spring 上下文一起运行测试,以便框架执行必须在内部完成的所有步骤,以返回正确的 HATEOAS 响应。

最好使用 TestRestTemplate,因为它是与 jayway 和 AssertJ 库一起使用的 Spring 解决方案。即使您正在进行 TDD,这也会使测试变得更容易

下面我留下一个来自Spring Academy

的例子
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class CashCardApplicationTests {
@Autowired
TestRestTemplate restTemplate;

@Test
void shouldReturnACashCardWhenDataIsSaved() {
    ResponseEntity<String> response = restTemplate.getForEntity("/cashcards/99", String.class);
    assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);

    DocumentContext documentContext = JsonPath.parse(response.getBody());
    Number id = documentContext.read("$.id");
    assertThat(id).isEqualTo(99);

    Double amount = documentContext.read("$.amount");
    assertThat(amount).isEqualTo(123.45);
}
}

使用与此类似的结构,您可以轻松执行所有断言和测试

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