Java 使用步进检验器对通量进行单元测试(持续时间)

Java 使用步进检验器对通量进行单元测试(持续时间),java,spring,unit-testing,project-reactor,Java,Spring,Unit Testing,Project Reactor,我使用的是Spring反应堆堆芯3.0.6,我有一种返回通量的方法: public Flux<Foo> createFlux(){ return Flux.<List<Foo>,String>generate(/* generator omitted for clarity's sake */ ) .take(Duration.ofSeconds(10) .flatMap(Flux::fromIterable); }

我使用的是Spring反应堆堆芯3.0.6,我有一种返回通量的方法:

public Flux<Foo> createFlux(){
    return Flux.<List<Foo>,String>generate(/* generator omitted for clarity's sake */ )
        .take(Duration.ofSeconds(10)
        .flatMap(Flux::fromIterable);
}
但它失败了:

java.lang.AssertionError: expectation "expectComplete" failed (expected: onComplete(); actual: onNext([my toString() Foo bean]))
我想我应该以某种方式使用生成的项目,但是我找不到正确的StepVerifier方法来这样做

编辑

我尝试用
跳过每一项,然后使用
跳过每一项:

StepVerifier.withVirtualTime(() -> createFlux())
    .thenAwait(Duration.ofSeconds(10))
    .thenConsumeWhile(t -> true)
    .verifyComplete();
但是现在,测试只是无限期地运行,永远不会结束。

如果您错过了测试,也许测试可以让您走上正确的道路


除了最常见的
expectNext
(您必须对序列中的每个项目重复)之外,如果您知道元素的数量或
thencumbers,您可以使用
expectNextCount
,而要根据谓词跳过元素,

生成器实际上可能非常重要
StepVerifier
受无限序列的限制,使用虚拟时间时更是如此。问题是生成器和等待
都在主线程中运行,因此生成器是无限的,这会阻止stepverifier提前时间,进而阻止序列超时

因为您想测试
的持续时间,所以我认为虚拟时间是不对的(您测试的是模拟时间)。我将使createFlux方法可以用take duration参数化,并在更短的时间内执行
StepVerifier.create()

如果你真的想使用某种形式的虚拟时间,我发现让它工作的最低要求是

  • 通过在测试开始时实例化
    调度程序
    ,隔离非虚拟线程上的生成器循环,然后在StepVerifier的
    供应商
    中使用
    订阅(调度程序)
  • 通过先调用
    .expectNextCount(1)
    ,确保所有内容都已订阅,数据开始流动,然后再尝试提前计时
  • 像这样:

    public Flux<Integer> createFlux() {
        return Flux.<List<Integer>>generate(sink -> {
            sink.next(Arrays.asList(1, 2, 3));
        })
                .take(Duration.ofSeconds(10))
                .flatMap(Flux::fromIterable);
    }
    
    @Test
    public void so44657525() throws InterruptedException {
        Scheduler scheduler = Schedulers.newSingle("test");
        AtomicInteger adder = new AtomicInteger();
    
        StepVerifier.withVirtualTime(() -> createFlux()
                .subscribeOn(scheduler)
                .doOnNext(v -> adder.incrementAndGet())
        )
                    .expectNextCount(1)
                    .thenAwait(Duration.ofSeconds(10))
                    .thenConsumeWhile(t -> true)
                    .verifyComplete();
    
        System.out.println("Total number of values in generated lists: " + adder.get());
    }
    
    public Flux createFlux(){
    返回通量。生成(汇->{
    sink.next(Arrays.asList(1,2,3));
    })
    .take(持续时间秒(10))
    .flatMap(通量::fromIterable);
    }
    @试验
    public void so44657525()引发InterruptedException{
    Scheduler=Schedulers.newSingle(“测试”);
    AtomicInteger加法器=新的AtomicInteger();
    带有虚拟时间(()->createFlux()的步骤验证程序
    .subscribeOn(调度程序)
    .doOnNext(v->adder.incrementAndGet())
    )
    .expectNextCount(1)
    .然后等待(持续时间秒(10))
    .ThenConsumerwhile(t->true)
    .verifyComplete();
    System.out.println(“生成列表中的值总数:“+adder.get()”);
    }
    

    expectNextCount(1)
    修改为
    expectNextCount(100_000)
    ,我运行了一次,打印了生成列表中的
    值总数:102405
    ,耗时40ms。

    我在3.0.6或3.0.7中找不到
    consumernextwhile
    ;因为我不想对序列进行断言,所以我在
    之后加了一个
    。然后在
    之后加上consumerwhile(t->true)
    ,然后等待
    ,跳过每个元素,只检查持续时间,但测试运行不确定,确实有效。我只做了一个更改:我使用
    .expectComplete().verifyComplete()来代替
    .verifyComplete()
    。这样,如果通量运行超过10秒,它将抛出断言错误。使用verifyComplete,它将无限期运行。如果通量运行预期的10秒,两种解决方案都可以。
    public Flux<Integer> createFlux() {
        return Flux.<List<Integer>>generate(sink -> {
            sink.next(Arrays.asList(1, 2, 3));
        })
                .take(Duration.ofSeconds(10))
                .flatMap(Flux::fromIterable);
    }
    
    @Test
    public void so44657525() throws InterruptedException {
        Scheduler scheduler = Schedulers.newSingle("test");
        AtomicInteger adder = new AtomicInteger();
    
        StepVerifier.withVirtualTime(() -> createFlux()
                .subscribeOn(scheduler)
                .doOnNext(v -> adder.incrementAndGet())
        )
                    .expectNextCount(1)
                    .thenAwait(Duration.ofSeconds(10))
                    .thenConsumeWhile(t -> true)
                    .verifyComplete();
    
        System.out.println("Total number of values in generated lists: " + adder.get());
    }