引言
如果你还不了解什么是软断言(Soft Assert),请阅读《软断言——为何你应在单元测试和集成测试中使用它们?》。
本文是《优雅断言:使用AssertJ创建自定义断言以实现更整洁的代码》的续篇,该文章向你展示了如何使用AssertJ创建自定义断言。在这里,你将学习如何在其方法的基础上进行扩展,从而在自定义断言之上使用软断言方法。
使用AssertJ创建自定义软断言
你可以使用AssertJ库中的Assertions类来实现硬断言,或者创建自定义断言。为了充分利用软断言的优势,我们需要:
- 实现一个自定义断言
- 创建自定义软断言类,并继承AssertJ中的AbstractSoftAssertions类
自定义断言
在《优雅断言:使用AssertJ创建自定义断言以实现更整洁的代码》一文中,你已经学习了如何创建自定义断言。它看起来像这样:
<pre>public class SimulationAssert extends AbstractAssert<SimulationAssert, Simulation> {
protected SimulationAssert(Simulation actual) {
super(actual, SimulationAssert.class);
}
public static SimulationAssert assertThat(Simulation actual) {
return new SimulationAssert(actual);
}
public SimulationAssert hasValidInstallments() {
isNotNull();
if (actual.getInstallments() < 2 || actual.getInstallments() >= 48) {
failWithMessage("Installments must be must be equal or greater than 2 and equal or less than 48");
}
return this;
}
public SimulationAssert hasValidAmount() {
isNotNull();
var minimum = new BigDecimal("1.000");
var maximum = new BigDecimal("40.000");
if (actual.getAmount().compareTo(minimum) < 0 || actual.getAmount().compareTo(maximum) > 0) {
failWithMessage("Amount must be equal or greater than $ 1.000 or equal or less than than $ 40.000");
}
return this;
}
}</pre>
自定义断言的使用不仅使测试更具可读性,而且还将测试有效值的责任委托给了它:
<pre>class SimulationsCustomAssertionTest {
@Test
void simulationErrorAssertion() {
var simulation = Simulation.builder().name("John").cpf("9582728395").email("john@gmail.com")
.amount(new BigDecimal("1.500")).installments(5).insurance(false).build();
SimulationAssert.assertThat(simulation).hasValidInstallments();
SimulationAssert.assertThat(simulation).hasValidAmount();
}
}</pre>
有了自定义断言在手,现在是时候实现自定义软断言了。
创建自定义软断言
创建自定义软断言有一个简单的过程,其前提是已经实现了自定义断言。根据上一篇文章,我们已经有了SimulationAssert类作为自定义断言,现在将创建SimulationSoftAssert作为自定义软断言。以下是具体步骤:
- 继承AbstractSoftAssertions类
-
创建assertThat()方法,包括:
- 方法返回对象作为自定义断言类
- 一个指向断言主体的参数
- 方法返回方法代理,其参数为自定义断言类和断言主体
-
创建assertSoftly()方法,包括:
-
一个指向自定义软断言类的Consumer参数
- 使用SoftAssertionsProvider.assertSoftly()方法,其中参数为自定义软断言类和方法参数
这些步骤看起来复杂,但实际上,你最终会得到如下内容:
<pre>public class SimulationSoftAssert extends AbstractSoftAssertions {
public SimulationAssert assertThat(Simulation actual) {
return proxy(SimulationAssert.class, Simulation.class, actual);
}
public static void assertSoftly(Consumer<SimulationSoftAssert> softly) {
SoftAssertionsProvider.assertSoftly(SimulationSoftAssert.class, softly);
}
}</pre>
使用自定义软断言
AssertJ的SoftAssertion类负责软断言。以下是一个适用于模拟(Simulation)场景的示例:
<pre>@Test
public void normalSoftAssertion() {
SoftAssertions.assertSoftly(softly -> {
var simulation = Simulation.builder().name("John").cpf("9582728395").email("john@gmail.com")
.amount(new BigDecimal("500")).installments(1).insurance(false).build();
softly.assertThat(simulation.getInstallments()).isEqualTo(1);
softly.assertThat(simulation.getAmount()).isEqualTo(500);
});
}</pre>
使用它(指直接使用SoftAssertions类)的“问题”在于,我们将无法使用已经创建的自定义断言。在上面的示例中,你可以看到安装分期和金额的断言使用了isEqualTo(),这是因为SoftAssertions类无法访问自定义断言。
我们通过创建自定义软断言类解决了这个问题。因此,我们将不再使用SoftAssertions类,而是使用自定义的SimulationSoftAssert类。
<pre>@Test
void simulationValidationErrorSoftAssertion() {
var simulation = Simulation.builder().name("John").cpf("9582728395").email("john@gmail.com")
.amount(new BigDecimal("500")).installments(1).insurance(false).build();
SimulationSoftAssert.assertSoftly(softly -> {
softly.assertThat(simulation).hasValidInstallments();
softly.assertThat(simulation).hasValidAmount();
});
}</pre>
SimulationSoftAssert.assertSoftly()
是软断言的提供者,它会调用所有内部方法来管理断言过程中的错误和其他活动。在 assertSoftly()
内部使用的 assertThat()
是自定义的,它能够通过软断言和断言对象之间的 proxy()
访问自定义断言。
使用这种方法,我们通过实现自定义软断言类,在软断言中提供了自定义断言。
结束
就这些啦,各位!
在credit-api项目中,你可以找到一个完全实现且可运行的示例,在那里你可以看到以下内容:
- SimulationAssert 类
- 以及SimulationCustomAssertionTest 类中的测试用法