使用AssertJ来断言同一对象上的多个JsonNode路径?

huangapple go评论57阅读模式
英文:

Using AssertJ to assert multiple JsonNode paths on the same object?

问题

I'm using assertj-core 3.9.1, but I also tested this with the latest available to me, 3.16.1.

我正在使用 assertj-core 3.9.1,但我也测试了最新的版本,3.16.1。

I'm trying to make some assertj assertions a little cleaner. We often assert multiple subproperties at a non-trivial hierarchy level, for various kinds of objects. I've been using "extracting" to pull simple properties from an object, but what I'm trying to do now is a little more complicated, and it's not working. What I'm seeing SEEMS like a bug in assertj, but I'm not sure why it's doing what it's doing.

我试图使一些 assertj 断言更加简洁。我们经常在不太常见的层次结构层级上断言多个子属性,针对各种类型的对象。我一直在使用 "extracting" 从对象中提取简单的属性,但我现在尝试做的更复杂,却不起作用。我所看到的情况似乎是 assertj 的一个 bug,但我不确定为什么它会出现这种情况。

I'm starting with something like this:

我从类似于以下内容的东西开始:

assertThat(expression).at("/content/liability").asText()).isEqualTo("CRU");
assertThat(expression).at("/content/enterpriseType").asText()).isEqualTo("GBS");

I'd like to instead do something like this:

我想改成这样:

assertThat(expression)
    .extracting(jn -> jn.at("/content/liability").asText(),
                jn -> jn.at("/content/enterpriseType").asText())
	.containsExactly("CRU", "GBS");

This fails, basically saying that I expected "[]" (an empty list) to be equal to ["CRU", "GBS"].

这会失败,基本上是说我预期 "[]"(空列表)与 ["CRU", "GBS"] 相等。

I still have the original assertions above this, using the same expression, so I know the data is there. The expression returns a structure like this:

我仍然在上面有原始的断言,使用相同的表达式,所以我知道数据是存在的。该表达式返回以下结构:

{
  "content": {
    ...
    "enterpriseType": "GBS",
    ...
    "liability": "CRU",
    ...
  }
}

So, I then tried changing the assertion to this:

所以,我尝试将断言更改为以下内容:

assertThat(expression))
	.extracting(jn -> textAtPath(jn, "/content/liability"),
				jn -> textAtPath(jn, "/content/enterpriseType"))
	.containsExactly(tuple("CRU", "GBS"));

With:

使用以下代码:

private String textAtPath(JsonNode node, String path) {
	return node.at(path).asText();
}

And then I ran the test with a breakpoint in "textAtPath". What I saw there looked normal, until I looked closer. When I viewed the value of "node", I saw something that looked very much like the structure I showed above, but not quite:

然后,我在 "textAtPath" 中设置了断点运行测试。我在那里看到的东西看起来很正常,直到我仔细观察。当我查看 "node" 的值时,我看到的东西非常类似于上面我展示的结构,但不完全相同:

{
  ...
  "enterpriseType": "GBS",
  ...
  "liability": "CRU",
  ...
}

For some reason, the value passed to the lambda passed to "extracting()" was the CHILD node of the original structure.

出于某种原因,传递给 "extracting()" 的 lambda 的值是原始结构的子节点。

I tried changing the test so the two path strings were "/liability" and "/enterpriseType". The test passed. I'm not going to leave it like this, because this just doesn't make sense.

我尝试将测试更改为两个路径字符串分别是 "/liability" 和 "/enterpriseType"。测试通过了。我不会让它保持这样,因为这没有意义。

英文:

I'm using assertj-core 3.9.1, but I also tested this with the latest available to me, 3.16.1.

I'm trying to make some assertj assertions a little cleaner. We often assert multiple subproperties at a non-trivial hierarchy level, for various kinds of objects. I've been using "extracting" to pull simple properties from an object, but what I'm trying to do now is a little more complicated, and it's not working. What I'm seeing SEEMS like a bug in assertj, but I'm not sure why it's doing what it's doing.

I'm starting with something like this:

assertThat(expression).at("/content/liability").asText()).isEqualTo("CRU");
assertThat(expression).at("/content/enterpriseType").asText()).isEqualTo("GBS");

I'd like to instead do something like this:

assertThat(expression)
    .extracting(jn -> jn.at("/content/liability").asText(),
                jn -> jn.at("/content/enterpriseType").asText())
	.containsExactly("CRU", "GBS");

This fails, basically saying that I expected "[]" (an empty list) to be equal to ["CRU", "GBS"].

I still have the original assertions above this, using the same expression, so I know the data is there. The expression returns a structure like this:

{
  "content": {
	...
	"enterpriseType": "GBS",
	...
	"liability": "CRU",
	...
  }
}

So, I then tried changing the assertion to this:

assertThat(expression))
	.extracting(jn -> textAtPath(jn, "/content/liability"),
				jn -> textAtPath(jn, "/content/enterpriseType"))
	.containsExactly(tuple("CRU", "GBS"));

With:

private String textAtPath(JsonNode node, String path) {
	return node.at(path).asText();
}

And then I ran the test with a breakpoint in "textAtPath". What I saw there looked normal, until I looked closer. When I viewed the value of "node", I saw something that looked very much like the structure I showed above, but not quite:

{
  ...
  "enterpriseType": "GBS",
  ...
  "liability": "CRU",
  ...
}

For some reason, the value passed to the lambda passed to "extracting()" was the CHILD node of the original structure.

I tried changing the test so the two path strings were "/liability" and "/enterpriseType". The test passed. I'm not going to leave it like this, because this just doesn't make sense.

答案1

得分: 0

我相信这个问题在 https://github.com/joel-costigliola/assertj-core/issues/1954 中有讨论。

这里的微妙之处在于,如果表达式是可迭代的,那么 assertThat(expression) 将提供可迭代的断言,并且 extracting 将应用于可迭代的元素。

另一方面,如果 assertThat(expression) 返回对象断言,extracting 将应用于表达式。

我还强烈建议使用 JsonUnit 进行 JSON 断言。

英文:

I believe this is discussed in https://github.com/joel-costigliola/assertj-core/issues/1954.

The subtlety here is that if expression is an iterable, assertThat(expression) will provide iterable assertions and extracting will be applied on the iterable elements.

On the other hand if assertThat(expression) has returned object assertion, extracting would be applied to expression.

I also strongly suggest to use JsonUnit for JSON assertions.

huangapple
  • 本文由 发表于 2020年8月1日 05:46:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/63199483.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定