Reactive - 04 - StepVerifier

翻译自:https://tech.io/playgrounds/929/reactive-programming-with-reactor-3/StepVerifier

StepVerifier


Description


Until now, your solution for each exercise was checked by passing the Publisher
you defined to a test using a StepVerifier.

到目前为止,每个练习的解决方案都是通过使用StepVerifier将定义的发布者传递到test来检查的。

This class from the reactor-test artifact is capable of subscribing to
any Publisher (eg. a Flux or an Akka Stream...) and then assert a set
of user-defined expectations with regard to the sequence.

此类来自于reactor-test,能够订阅任何发布者(例如,Flux或Akka Stream),
然后断言一组用户定义的关于序列的期望。

If any event is triggered that doesn't match the current expectation,
the StepVerifier will produce an AssertionError.

如果触发的任何事件与当前预期不匹配,StepVerifier将生成一个AssertionError。

You can obtain an instance of StepVerifier from the static factory create.
It offers a DSL to set up expectations on the data part and finish with a
single terminal expectation (completion, error, cancellation...).

您可以从静态工厂方法create获取StepVerifier的实例。它提供了一个DSL来设置数据部分的期望,
并以单个终端期望(完成、错误、取消)结束。

Note that you must always call the verify() method or one of the shortcuts
that combine the terminal expectation and verify, like .verifyErrorMessage(String).
Otherwise the StepVerifier won't subscribe to your sequence and nothing will
be asserted.

请注意,您必须始终调用verify()方法或verify结合终端期望的快捷方式之一(verifyComplete或verifyError),
例如.verifyErrorMessage(String)。否则,StepVerifier将不会订阅您的序列,并且不会断言任何内容。
StepVerifier.create(T<Publisher>)
.{expectations...}.verify()

Practice


In these exercises, the methods get a Flux or Mono as a parameter and you'll
need to test its behavior. You should create a StepVerifier that uses said
Flux/Mono, describes expectations about it and verifies it.

在这些练习中,这些方法将Flux或Mono作为参数,您需要测试其行为。您应该创建一个使用
所述Flux/Mono的StepVerifier,描述对它的期望并进行验证。

Let's verify the sequence passed to the first test method emits two specific elements,
"foo" and "bar", and that the Flux then completes successfully.

让我们验证传递给第一个测试方法的序列是否发出两个特定元素"foo"和"bar",然后验证通量是否成功完成。
    // Use StepVerifier to check that the flux parameter emits "foo" and "bar" elements then completes successfully.
    void expectFooBarComplete(Flux<String> flux) {
        StepVerifier.create(flux).expectNext("foo", "bar").verifyComplete();
    }

Now, let's do the same test but verifying that an exception is propagated at the end.

现在,让我们执行相同的测试,但验证是否在最后传播了异常。
    // Use StepVerifier to check that the flux parameter emits "foo" and "bar" elements then a RuntimeException error.
    void expectFooBarError(Flux<String> flux) {
        StepVerifier.create(flux).expectNext("foo", "bar").verifyError(RuntimeException.class);
    }

Let's try to create a StepVerifier with an expectation on a User's
getUsername() getter. Some expectations can work by checking a Predicate
on the next value, or even by consuming the next value by passing it to
an assertion library like Assertions.assertThat(T) from AssertJ.
Try these lambda-based versions (for instance StepVerifier#assertNext
with a lambda using an AssertJ assertion like assertThat(...).isEqualTo(...)):

让我们尝试创建一个StepVerifier,期望User.getUsername()。
有些期望可以通过检查下一个值的Predicate谓词来实现,
甚至可以通过将下一个值传递给 类似断言的断言库 比如AssertJ的assertThat(T)。
尝试这些基于lambda的版本(例如StepVerifier#assertNext使用AssertJ断言的lambda,
如assertThat(...).isEqualTo(...)
    // Use StepVerifier to check that the flux parameter emits a User with "swhite"username
    // and another one with "jpinkman" then completes successfully.
    void expectSkylerJesseComplete(Flux<User> flux) {
        StepVerifier.create(flux)
                .expectNextMatches(user -> user.getUsername().equals("swhite"))
                .assertNext(user -> Assertions.assertThat(user.getUsername()).isEqualToIgnoringCase("jpinkman"))
                .verifyComplete();
    }

On this next test we will receive a Flux which takes some time to emit.
As you can expect, the test will take some time to run.

在下一个测试中,我们将收到一个需要一些时间才能发射的Flux。正如您所料,测试将需要一些时间才能运行。
    // Expect 10 elements then complete and notice how long the test takes.
    void expect10Elements(Flux<Long> flux) {
        StepVerifier.create(flux).expectNextCount(10).verifyComplete();
    }

The next one is even worse: it emits 1 element per second,
completing only after having emitted 3600 of them!

下一个更糟糕:它每秒发射1个元素,只有在发射3600个元素后才能完成!

Since we don't want our tests to run for hours, we need a way to speed that
up while still being able to assert the data itself (eliminating the time factor).

由于我们不想让测试运行数小时,我们需要一种方法来加快速度,同时仍然能够断言数据本身(消除时间因素)。

Fortunately, StepVerifier comes with a virtual time option:
by using StepVerifier.withVirtualTime(Supplier<Publisher>), the verifier
will temporarily replace default core Schedulers (the component that define
the execution context in Reactor). All these default Scheduler are replaced
by a single instance of a VirtualTimeScheduler, which has a virtual clock
that can be manipulated.

幸运的是,StepVerifier附带了一个虚拟时间选项:
通过使用StepVerifier.withVirtualTime(Supplier<Publisher>),验证器将临时替换默认的
核心调度程序(定义反应堆中执行上下文的组件)。所有这些默认调度程序都被VirtualTimeScheduler
的单个实例取代,该实例具有一个可以操纵的虚拟时钟。

In order for the operators to pick up that Scheduler, you should lazily build
your operator chain inside the lambda passed to withVirtualTime.

为了让运算符选择该调度器,您应该在传递给withVirtualTime的lambda内懒惰地构建运算符链。

You must then advance time as part of your test scenario, by calling either
thenAwait(Duration) or expectNoEvent(Duration). The former simply advances
the clock, while the later additionally fails if any unexpected event triggers
during the provided duration (note that almost all the time there will at least
be a "subscription" event even though the clock hasn't advanced, so you should
usually put a expectSubscription() after .withVirtualTime() if you're going
to use expectNoEvent right after).

然后,您必须将时间推进作为测试场景的一部分,方法是调用thenAwait(Duration)或expectNoEvent(Duration)。
前者只是使时钟提前,而如果在提供的持续时间内触发任何意外事件,则后者会额外失败(请注意,
即使时钟没有提前,几乎所有时间都至少会有一个“订阅”事件,因此如果您要在之后立即使用expectNoEvent,
通常应该在.withVirtualTime()后面放置一个expectSubscription())。
StepVerifier.withVirtualTime(() -> Mono.delay(Duration.ofHours(3)))
            .expectSubscription()
            .expectNoEvent(Duration.ofHours(2))
            .thenAwait(Duration.ofHours(1))
            .expectNextCount(1)
            .expectComplete()
            .verify();

Let's try that by making a fast test of our hour-long publisher:

让我们来尝试这一点,通过快速测试我们长达一小时的发布者
    // Expect 3600 elements at intervals of 1 second, and verify quicker than 3600s
    // by manipulating virtual time thanks to StepVerifier#withVirtualTime, notice how long the test takes
    void expect3600Elements(Supplier<Flux<Long>> supplier) {
        StepVerifier.withVirtualTime(supplier).thenAwait(Duration.ofHours(1)).expectNextCount(3600).verifyComplete();
    }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容