Reactor学习--测试
前面的例子中都使用了System.out.println方法输出数据的方式来验证程序。这种方式需要人工去验证结果是否正确并且无法在单元测试中使用。Reactor为测试准备了相关的工具库reactor-test。
引入reactor-test依赖,我们这里在main中使用reactor-test中工具类,所以scope为默认即可。
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
</dependency>
StepVerifier
reactor-test核心接口为StepVerifier,该接口提供了若干的静态工厂方法,从待测试的Publisher创建测试步骤。测试步骤被抽象为状态机接口FirstStep、Step和LastStep,分别代表了测试的初始阶段、中间阶段和最终阶段。这些Step上都具有一系列的expect和assert方法,用于测试当前状态是否符合预期。
使用StepVerifier测试Publisher的套路如下:
- 首先将已有的Publisher传入StepVerifier的create方法。
- 多次调用expectNext、expectNextMatches方法设置断言,验证Publisher每一步产生的数据是否符合预期。
- 调用expectComplete、expectError设置断言,验证Publisher是否满足正常结束或者异常结束的预期。
- 调用verify方法启动测试。
最简单的例子
public class SimpleExpect {
public static void main(String[] args) {
StepVerifier.create(Flux.just("one", "two","three"))
//依次校验每一步的数据是否符合预期
.expectNext("one")
.expectNext("two")
.expectNext("three")
//校验Flux流是否按照预期正常关闭
.expectComplete()
//启动
.verify();
}
}
如果Publisher满足测试的断言,StepVerifier会正常结束。如果不满足,则会抛出AssertionError异常,如下:
StepVerifier.create(Flux.just("one", "two","three"))
//依次校验每一步的数据是否符合预期
.expectNext("one")
.expectNext("two")
//不满足预期,抛出异常
.expectNext("Five")
//校验Flux流是否按照预期正常关闭
.expectComplete()
//启动
.verify();
输出:Exception in thread "main" java.lang.AssertionError: expectation "expectNext(Five)" failed (expected value: Five; actual value: three) 异常信息中输出了断言失败的原因。
异常断言
可以使用expectError方法对抛出的异常进行断言。
public class ExpectError {
public static void main(String[] args) {
Flux<Integer> integerFluxWithException = Flux.just(
new DivideIntegerSupplier(1, 2),
new DivideIntegerSupplier(8, 2),
new DivideIntegerSupplier(20, 10),
//异常数据,抛出ArithmeticException
new DivideIntegerSupplier(1, 0),
new DivideIntegerSupplier(2, 2)
).map(divideIntegerSupplier -> divideIntegerSupplier.get());
StepVerifier.create(integerFluxWithException)
.expectNext(1 / 2)
.expectNext(8 / 2)
.expectNext(20 / 10)
//校验异常数据,可以判断抛出的异常的类型是否符合预期
.expectError(ArithmeticException.class)
.verify();
}
}
assertNext方法、expectNextMatches方法、thenConsumeWhile方法
之前的测试中,Publisher中数据的值都是确定的,所以可以使用expectNext进行判断,但是很多场景下,数据的值不完全确定,只知道数据的特征或者数据量太大,无法一一写出具体的值,此时assertNext方法、expectNextMatches方法、thenConsumeWhile方法可以满足此类需求。
assertNext方法需要利用第三方断言库,如junit断言进行校验,使用此方法,即可将StepVerifier集成到junit中。
expectNextMatches和thenConsumeWhile则直接传入Predicate进行判断。
thenConsumeWhile会持续获取并判断数据,直到不满足Predicate为止。
如下例子:
public class ThenConsumeWhile {
public static void main(String[] args) {
//素数数据流
Flux<Integer> primes = Flux.range(1, 100)
.filter(integer -> isPrime(integer));
StepVerifier.create(primes)
//素数肯定无法整除8
.thenConsumeWhile(integer -> (integer % 8 != 0))
.verifyComplete();
}
private static boolean isPrime(int n) {
if (n < 2) {
return false;
}
if (n == 2) {
return true;
}
if (n % 2 == 0) {
return false;
}
for (int i = 3; i < n; i += 2) {
if (n % i == 0) {
return false;
}
}
return true;
}
}
如下例子集成junit
public class TestAssertNext {
@Test
public void test() {
Flux<Integer> just = Flux.just(1, 2, 3);
StepVerifier.create(just)
.assertNext(integer -> {
assertEquals(1, integer.intValue());
}).assertNext(integer -> {
assertEquals(2, integer.intValue());
}).assertNext(integer -> {
assertEquals(3, integer.intValue());
}).verifyComplete();
}
}
运行结果如下: