JUnit5:如何通过单个断言调用断言一个对象的多个属性?
JUnit5: How to assert several properties of an object with a single assert call?
我想通过一次断言调用断言一个对象的多个属性。
使用 JUnit 4 和 Hamcrest 我会写这样的东西:
assertThat(product, allOf(
hasProperty("name", is("Coat")),
hasProperty("available", is(true)),
hasProperty("amount", is(12)),
hasProperty("price", is(new BigDecimal("88.0")))
));
问:如何使用 JUnit 5 和 AssertJ 在单个断言调用中断言多个属性?或者,在 JUnit 5 世界中,最好的方法是什么。
注意:我当然可以创建一个具有所有需要的属性的对象并执行
assertThat(actualProduct, is(expectedProduct))
但这不是重点。
与 AssertJ 最接近的是:
assertThat(product).extracting("name", "available", "amount", "price")
.containsExactly("Coat", true, 12, new BigDecimal("88.0"));
但我不喜欢用 String
引用字段名称,因为它们作为字段名称的有效性仅在运行时检查(已知的反射问题)并且这些 String
可能在我们从 IDE 执行的重构操作期间也被错误地更新。
虽然有点冗长,但我更喜欢:
assertThat(product).extracting(Product::getName, Product::getAvailable,
Product::getAmount, Product::getPrice)
.containsExactly("Coat", true, 12, new BigDecimal("88.0"));
您引用的 AssertJ 相对于 Hamcrest 的优势在于它非常流畅:因此在大多数情况下,您需要单个导入:import org.assertj.core.api.Assertions;
并且对于集合断言,有时需要:org.assertj.core.groups.Tuple;
这里是 JUnit 5 或 4;这并不重要,因为对于非常简单的情况,您只会将 JUnit 用作测试运行程序,而让 AssertJ 执行断言。
Or, alternatively, what is the best way of doing that in JUnit 5
universe.
JUnit 5(作为第 4 版)不提供灵活流畅的断言功能。因此,使用 JUnit 5 的最佳方式来做这件事必然会产生更多的样板代码:断言与要断言或覆盖的字段一样多 equals()/hashCode()
出于公平原因要避免的覆盖。
您可以使用 Assertions.assertAll
:
assertAll("product",
() -> assertEquals("Coat", product.getName()),
() -> assertTrue(product.isAvaikable())
);
assertAll 可以接受任意多的单独断言。这是用户指南部分的 link:https://junit.org/junit5/docs/current/user-guide/#writing-tests-assertions
对于 AssertJ,另一种选择是使用 returns
:
assertThat(product)
.returns("Coat", from(Product::getName)),
.returns(true, from(Product::getAvailable)),
.returns(12, from(Product::getAmount)),
.returns(new BigDecimal("88.0"), from(Product::getPrice));
有点冗长,但我发现它比 extracting
/contains
.
更容易阅读
请注意,from
只是一个可选的语法糖,用于提高可读性。
从 3.22.0 开始,doesNotReturn
也可用。这对于事先不知道预期值的非空字段很有用。
assertThat(product)
.returns("Coat", from(Product::getName)),
.returns(true, from(Product::getAvailable)),
.doesNotReturn(42, from(Product::getAmount)),
.doesNotReturn(null, from(Product::getPrice));
我想通过一次断言调用断言一个对象的多个属性。
使用 JUnit 4 和 Hamcrest 我会写这样的东西:
assertThat(product, allOf(
hasProperty("name", is("Coat")),
hasProperty("available", is(true)),
hasProperty("amount", is(12)),
hasProperty("price", is(new BigDecimal("88.0")))
));
问:如何使用 JUnit 5 和 AssertJ 在单个断言调用中断言多个属性?或者,在 JUnit 5 世界中,最好的方法是什么。
注意:我当然可以创建一个具有所有需要的属性的对象并执行
assertThat(actualProduct, is(expectedProduct))
但这不是重点。
与 AssertJ 最接近的是:
assertThat(product).extracting("name", "available", "amount", "price")
.containsExactly("Coat", true, 12, new BigDecimal("88.0"));
但我不喜欢用 String
引用字段名称,因为它们作为字段名称的有效性仅在运行时检查(已知的反射问题)并且这些 String
可能在我们从 IDE 执行的重构操作期间也被错误地更新。
虽然有点冗长,但我更喜欢:
assertThat(product).extracting(Product::getName, Product::getAvailable,
Product::getAmount, Product::getPrice)
.containsExactly("Coat", true, 12, new BigDecimal("88.0"));
您引用的 AssertJ 相对于 Hamcrest 的优势在于它非常流畅:因此在大多数情况下,您需要单个导入:import org.assertj.core.api.Assertions;
并且对于集合断言,有时需要:org.assertj.core.groups.Tuple;
这里是 JUnit 5 或 4;这并不重要,因为对于非常简单的情况,您只会将 JUnit 用作测试运行程序,而让 AssertJ 执行断言。
Or, alternatively, what is the best way of doing that in JUnit 5 universe.
JUnit 5(作为第 4 版)不提供灵活流畅的断言功能。因此,使用 JUnit 5 的最佳方式来做这件事必然会产生更多的样板代码:断言与要断言或覆盖的字段一样多 equals()/hashCode()
出于公平原因要避免的覆盖。
您可以使用 Assertions.assertAll
:
assertAll("product",
() -> assertEquals("Coat", product.getName()),
() -> assertTrue(product.isAvaikable())
);
assertAll 可以接受任意多的单独断言。这是用户指南部分的 link:https://junit.org/junit5/docs/current/user-guide/#writing-tests-assertions
对于 AssertJ,另一种选择是使用 returns
:
assertThat(product)
.returns("Coat", from(Product::getName)),
.returns(true, from(Product::getAvailable)),
.returns(12, from(Product::getAmount)),
.returns(new BigDecimal("88.0"), from(Product::getPrice));
有点冗长,但我发现它比 extracting
/contains
.
请注意,from
只是一个可选的语法糖,用于提高可读性。
从 3.22.0 开始,doesNotReturn
也可用。这对于事先不知道预期值的非空字段很有用。
assertThat(product)
.returns("Coat", from(Product::getName)),
.returns(true, from(Product::getAvailable)),
.doesNotReturn(42, from(Product::getAmount)),
.doesNotReturn(null, from(Product::getPrice));