使用虚拟时间测试基于时间的反应堆堆芯流

位置:首页>文章>详情   分类: Java教程 > 编程技术   阅读(401)   2024-01-27 15:34:57

Reactor Core 实现了 Reactive Streams 规范并处理(可能是无限的)数据流。如果您对它感兴趣,请查看它提供的出色的文档。在这里,我假设对 Reactor Core 库 FluxMono 类型有一些基本的了解,并将介绍 Reactor Core 提供了时间本身的抽象,以便能够测试依赖于通道的函数的时间。

对于 Reactor-core 的某些操作符,时间是一个重要的考虑因素——例如,“间隔”函数的变体在 10 秒的初始“延迟”后每 5 秒发出一个递增的数字:

val flux = Flux
        .interval(Duration.ofSeconds(10), Duration.ofSeconds(5))
        .take(3)

根据正常的时间流逝来测试这样的数据流是很糟糕的,这样的测试大约需要 20 秒才能完成。

Reactor-Core 提供了一种解决方案,一种对时间本身的抽象——基于虚拟时间的调度程序,它提供了一种以确定性方式测试这些类型操作的巧妙方法。

让我以两种方式展示它,一种显式方式应该使基于虚拟时间的调度程序的操作非常清楚,然后是使用 Reactor Core 进行测试的推荐方法。

import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import reactor.core.publisher.Flux
import reactor.test.scheduler.VirtualTimeScheduler
import java.time.Duration
import java.util.concurrent.CountDownLatch


class VirtualTimeTest {
    
    @Test
    fun testExplicit() {
        val mutableList = mutableListOf<Long>()

        val scheduler = VirtualTimeScheduler.getOrSet()
        val flux = Flux
                .interval(Duration.ofSeconds(10), Duration.ofSeconds(5), scheduler)
                .take(3)

        val latch = CountDownLatch(1)
        
        flux.subscribe({ l -> mutableList.add(l) }, { _ -> }, { latch.countDown() })
        
        scheduler.advanceTimeBy(Duration.ofSeconds(10))
        assertThat(mutableList).containsExactly(0L)
        
        scheduler.advanceTimeBy(Duration.ofSeconds(5))
        assertThat(mutableList).containsExactly(0L, 1L)
        
        scheduler.advanceTimeBy(Duration.ofSeconds(5))
        assertThat(mutableList).containsExactly(0L, 1L, 2L)

        latch.await()
    }
    
}

1. 首先,“Flux.interval”函数的调度器被设置为基于虚拟时间的调度器。

2. 数据流预计在 10 秒延迟后每 5 秒发射一次

3. VirtualTimeScheduler 提供了一个“advanceTimeBy”方法来将虚拟时间提前一个 Duration,因此时间首先被提前 10 秒的延迟时间,此时第一个元素(0)预计将被发射

4. 随后两次提前5秒,分别得到1和2。

这是确定性的,测试会很快完成。这个版本的测试虽然丑陋,但它使用一个列表来收集和断言结果,并使用 CountDownLatch 来控制测试何时终止。一种更简洁的测试 Reactor-Core 类型的方法是使用优秀的 StepVerifier 类,使用此类的测试如下所示:

import org.junit.Test
import reactor.core.publisher.Flux
import reactor.test.StepVerifier
import reactor.test.scheduler.VirtualTimeScheduler
import java.time.Duration

class VirtualTimeTest {

    @Test
    fun testWithStepVerifier() {

        VirtualTimeScheduler.getOrSet()
        val flux = Flux
                .interval(Duration.ofSeconds(10), Duration.ofSeconds(5))
                .take(3)

        StepVerifier.withVirtualTime({ flux })
                .expectSubscription()
                .thenAwait(Duration.ofSeconds(10))
                .expectNext(0)
                .thenAwait(Duration.ofSeconds(5))
                .expectNext(1)
                .thenAwait(Duration.ofSeconds(5))
                .expectNext(2)
                .verifyComplete()
    }
 }

这个使用 StepVerifier 的新测试读起来很好,每一步都会提前时间并断言当时的预期。

标签2: Java教程
地址:https://www.cundage.com/article/jcg-testing-time-based-reactor-core-streams-virtual-time.html

相关阅读

Java HashSet 教程展示了如何使用 Java HashSet 集合。 Java哈希集 HashSet 是一个不包含重复元素的集合。此类为基本操作(添加、删除、包含和大小)提供恒定时间性...
SpringApplicationBuilder 教程展示了如何使用 SpringApplicationBuilder 创建一个简单的 Spring Boot 应用程序。 春天 是用于创建企业应...
通道是继 buffers 之后 java.nio 的第二个主要新增内容,我们在之前的教程中已经详细了解了这一点。通道提供与 I/O 服务的直接连接。 通道是一种在字节缓冲区和通道另一端的实体(通...
课程大纲 Elasticsearch 是一个基于 Lucene 的搜索引擎。它提供了一个分布式的、支持多租户的全文搜索引擎,带有 HTTP Web 界面和无模式的 JSON 文档。 Elasti...
解析器是强大的工具,使用 ANTLR 可以编写可用于多种不同语言的各种解析器。 在这个完整的教程中,我们将: 解释基础:什么是解析器,它可以用来做什么 查看如何设置 ANTLR 以便在 Java...
Java中的继承是指子类继承或获取父类的所有非私有属性和行为的能力。继承是面向对象编程的四大支柱之一,用于提高层次结构中类之间的代码可重用性。 在本教程中,我们将了解 Java 支持的继承类型,...
Java 是用于开发各种桌面应用程序、Web 应用程序和移动应用程序的最流行的编程语言之一。以下文章将帮助您快速熟悉 Java 语言,并迈向 API 和云开发等更复杂的概念。 1. Java语言...
Java Message Service 是一种支持正式通信的 API,称为 网络上计算机之间的消息传递。 JMS 为支持 Java 程序的标准消息协议和消息服务提供了一个通用接口。 JMS 提...
Java 项目中的一项常见任务是将日期格式化或解析为字符串,反之亦然。解析日期意味着你有一个代表日期的字符串,例如“2017-08-3”,你想把它转换成一个代表 Java 中日期的对象,例如Ja...
之前,我介绍了spring 3 + hibernate 集成 示例和struts 2 hello world 示例。在本教程中,我将讨论在将 spring 框架与 struts 与 hibern...