ASSERTJ:如何使jsonnode比较句柄intnode和longnode一样?

发布于 2025-02-08 23:31:40 字数 1783 浏览 2 评论 0原文

我有一个jsonnode,该是由map< string,object>的构建的:

Map<String, Object> actual = Map.of("test", 3L);
JsonNode actualNode = mapper.valueToTree(actual);

我想将此节点与预期的文件进行比较,我会加载这样的文件

String expected = "{\"test\": 3}";
JsonNode expectedNode = mapper.readTree(expected);

:我打印这两个节点,我发现它们完全相同:

>> System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(expectedNode));
>> System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(actualNode)); 

{
    "test": 3
}

但是,当我使用assert-j比较两个节点时,我会收到以下错误:

Assertions.assertThat(actualNode).isEqualTo(expectedNode);

java.lang.AssertionError: 
Expecting:
 <"{"test":3} (ObjectNode@7ef2d7a6)">
to be equal to:
 <"{"test":3} (ObjectNode@5dcbb60)">
but was not.

如果我调试.isequalto。的断言,我看到失败发生是因为:

  • 实际节点中的3longnode(我理解,因为原始映射包含a <代码> 3L )
  • 3在预期节点中是intnode

因此当测试等式时,intnode不是即使是longnode的实例,因此断言失败了。

但是,我真的无法控制MAP在实际节点背后的构建背后。在这种情况下,我该怎么做才能使断言起作用?

完全可重现的示例:

Map<String, Object> actual = Map.of("test", 3L);
String expected = "{\"test\": 3}";
ObjectMapper mapper = new ObjectMapper();
JsonNode expectedNode = mapper.readTree(expected);
JsonNode actualNode = mapper.valueToTree(actual);
Assertions.assertThat(actualNode).isEqualTo(expectedNode);

PS我目前已经通过序列化和划分节点来修复它:

JsonNode newActualNode = mapper.readTree(mapper.writeValueAsString(actualNode));

...但是我正在寻找更清洁的东西。

I have a JsonNode which is built out of a Map<String, Object>:

Map<String, Object> actual = Map.of("test", 3L);
JsonNode actualNode = mapper.valueToTree(actual);

I would like to compare such node against an expected file, that I load as such:

String expected = "{\"test\": 3}";
JsonNode expectedNode = mapper.readTree(expected);

When I print these two nodes, I see that they are exactly the same:

>> System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(expectedNode));
>> System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(actualNode)); 

{
    "test": 3
}

However, when I compare the two nodes using assert-j, I get the following error:

Assertions.assertThat(actualNode).isEqualTo(expectedNode);

java.lang.AssertionError: 
Expecting:
 <"{"test":3} (ObjectNode@7ef2d7a6)">
to be equal to:
 <"{"test":3} (ObjectNode@5dcbb60)">
but was not.

If I debug the .isEqualTo of the assertion, I see that the failure happens because:

  • The 3 in the actual node is a LongNode (which I understand since the original map contains a 3L)
  • The 3 in the expected node though is an IntNode

So when the equality is tested, the IntNode is not even an instanceof LongNode and so the assertion fails.

However, I really don't control how the Map behind the actual node is built. What can I do to make the assertion work in this case?

Fully reproducible example:

Map<String, Object> actual = Map.of("test", 3L);
String expected = "{\"test\": 3}";
ObjectMapper mapper = new ObjectMapper();
JsonNode expectedNode = mapper.readTree(expected);
JsonNode actualNode = mapper.valueToTree(actual);
Assertions.assertThat(actualNode).isEqualTo(expectedNode);

P.s. I have currently fixed it by serializing and deserializing the node:

JsonNode newActualNode = mapper.readTree(mapper.writeValueAsString(actualNode));

... but I was looking for something cleaner.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

网名女生简单气质 2025-02-15 23:31:40

原因是因为杰克逊(Jackson)默认为int,它可以适合未型值(即最多32位)。因此,assertj(甚至木星的断言)已经正确失败了断言,因为实际和预期的确实是两种不同的类型。此行为可以通过DeserializationFeature.USE_LONG_FOR_INTS功能控制。该物业的Java文档的最后一句话说。

默认情况下禁用功能,这意味着“未型”积分
如果值适合,则默认情况下将使用整数进行审理。

当创建ObjectMapper

mapper = new ObjectMapper().enable(DeserializationFeature.USE_LONG_FOR_INTS);

杰克逊将不必要地创建值的值时,您可以简单地启用它。

The reason is because the jackson defaults to int when it can fit in the untyped value (i.e up to 32 bit). So the assertj (even the jupiter assertions) has correctly failed the assertion, because actual and expected are indeed two different types. This behaviour can be controlled by the DeserializationFeature.USE_LONG_FOR_INTS feature. The last sentence of the java doc of that property says this;

Feature is disabled by default, meaning that "untyped" integral
numbers will by default be deserialized using Integer if value fits.

You can simply enable it when you create the ObjectMapper

mapper = new ObjectMapper().enable(DeserializationFeature.USE_LONG_FOR_INTS);

The downside is jackson will create values in larger long type unnecessarily.

淤浪 2025-02-15 23:31:40

正如您发现的那样,ASSERTJ在报告节点并不等于一个有一个长的孩子,而另一个则具有int。

您写道:

当我打印这两个节点时,我看到它们完全相同

证明了他们的toString方法产生相同的结果。这与它们完全相同。

如果您要寻找的是验证节点的toString,则:

assertThat(actualNode).hasToString(expectedNode.toString());

As you have discovered, AssertJ is behaving correctly in reporting that the nodes are not equal as one has a long child and the other has an int.

You wrote:

When I print these two nodes, I see that they are exactly the same

Printing the nodes using toString proves that their toString methods produce the same result. That's not the same as them being exactly the same.

If what you are looking for is to validate the toString of the node then:

assertThat(actualNode).hasToString(expectedNode.toString());
初见 2025-02-15 23:31:40

jsonunit with assertj样式可能是最好的选择:

assertThatJson(actualNode).isEqualTo(expectedNode); // passes

但是,我期望 assertj递归比较也可以正常工作:

assertThat(actualNode).usingRecursiveComparison().isEqualTo(expectedNode); // fails

但事实并非如此。

我创建了#2672 跟踪这种潜在的改进。

JsonUnit with AssertJ style is probably the best option:

assertThatJson(actualNode).isEqualTo(expectedNode); // passes

However, I would have expected the AssertJ recursive comparison to work as well:

assertThat(actualNode).usingRecursiveComparison().isEqualTo(expectedNode); // fails

but this is not the case.

I created #2672 to track this potential improvement.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文