异步校验工具 awaitility 快速入门

1.什么是awaitility ?

Awaitility 是一个用于 Java 的小型领域特定语言(DSL),主要用于简化和管理异步操作的同步问题。它的主要作用包括:

  1. 等待异步操作完成:在测试异步代码时,Awaitility 可以帮助你等待某个条件变为真,而不需要使用复杂的线程管理或轮询机制。

  2. 提高测试的可读性:通过使用流畅的 API,Awaitility 使得测试代码更易于阅读和理解。

  3. 减少测试中的线程问题 :避免在测试中显式地使用 Thread.sleep(),从而减少不必要的等待时间和线程问题。

  4. 灵活的超时和轮询间隔:允许你设置自定义的超时时间和轮询间隔,以便更好地控制等待条件的检查频率。

总之,Awaitility 使得在测试异步操作时更加简单和直观,特别是在需要等待某个条件满足的情况下。

2.代码工程

实验目的

一个使用 Awaitility 的简单示例,演示如何等待异步操作完成。假设我们有一个异步任务,该任务在后台线程中更新一个标志,我们希望在测试中等待这个标志变为 true

pom.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>Java-demo</artifactId>
        <groupId>com.et</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>Awaitility</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>
    <dependencies>
        <!-- Awaitility dependency -->
        <dependency>
            <groupId>org.awaitility</groupId>
            <artifactId>awaitility</artifactId>
            <version>4.2.0</version>
        </dependency>

        <!-- JUnit dependency for testing -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.8.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

AwaitilityExample

  1. 异步任务startAsyncTask 方法启动一个异步任务,该任务在 5秒后将 flag 设置为 true

  2. Awaitility 使用 :在 main 方法中,我们使用 Awaitility 的 await() 方法来等待 flag 变为 true。我们设置了一个最大等待时间为 5 秒。

  3. 条件检查until(example::isFlag) 表示我们等待 example.isFlag() 返回 true

    package com.et;

    import org.awaitility.Awaitility; import java.util.concurrent.TimeUnit; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;

    public class AwaitilityExample { private volatile boolean flag = false;

    scss 复制代码
    public void startAsyncTask() {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.submit(() -> {
            try {
                // mock async
                Thread.sleep(5000);
                flag = true;
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        executor.shutdown();
    }
    
    public boolean isFlag() {
        return flag;
    }
    
    public static void main(String[] args) {
        AwaitilityExample example = new AwaitilityExample();
        example.startAsyncTask();
    
        // use Awaitility to wait flag for true
        Awaitility.await()
                  .atMost(5, TimeUnit.SECONDS)
                  .until(example::isFlag);
    
        System.out.println("Flag is now true!");
    }

    }

以上只是一些关键代码,所有代码请参见下面代码仓库

代码仓库

3.测试代码

3-1.默认等待时间

await().until(Callable conditionEvaluator) 最多等待 10s 直到 conditionEvaluator 满足条件,否则 ConditionTimeoutException。

java 复制代码
@Test
public void testAsynchronousNormal() {
    AwaitilityExample example = new AwaitilityExample();
    example.startAsyncTask();
    try {
        // Default timeout is 10 seconds. If the condition is not met within this period, a ConditionTimeoutException is thrown
        Awaitility.await().until(new Callable<Boolean>() {
            @Override
            public Boolean call() throws Exception {
                return example.isFlag();
            }
        });
    } catch (Exception e) {
        Assertions.fail("Run exception: " + e.getMessage() + ", error: " + e.getStackTrace()[0].toString());
    }
}

3-2.最多等待

await().atMost() 设置最多等待时间,如果在这时间内条件还不满足,将抛出 ConditionTimeoutException。

java 复制代码
@Test
public void testAsynchronousAtMost() {
    AwaitilityExample example = new AwaitilityExample();
    example.startAsyncTask();
    try {
        // Specify a timeout of 3 seconds. If the condition is not met within this period, a ConditionTimeoutException is thrown
        Awaitility.await().atMost(3, SECONDS).until(new Callable<Boolean>() {
            @Override
            public Boolean call() throws Exception {
                return example.isFlag();
            }
        });
    } catch (Exception e) {
        Assertions.fail("Run exception: " + e.getMessage() + ", error: " + e.getStackTrace()[0].toString());
    }
}

3-3.至少等待

await().atLeast() 设置至少等待时间;多个条件时候用 and() 连接。

java 复制代码
@Test
public void testAsynchronousAtLeast() {
    AwaitilityExample example = new AwaitilityExample();
    example.startAsyncTask();

    try {
        // Specify at least 1 second and at most 3 seconds. If the condition is not met within this period, a ConditionTimeoutException is thrown
        Awaitility.await().atLeast(1, SECONDS).and().atMost(3, SECONDS).until(new Callable<Boolean>() {
            @Override
            public Boolean call() throws Exception {
                return example.isFlag();
            }
        });

    } catch (Exception e) {
        Assertions.fail("Run exception: " + e.getMessage() + ", error: " + e.getStackTrace()[0].toString());
    }
}

3-4.轮询

with().pollInterval(ONE_HUNDRED_MILLISECONDS).and().with().pollDelay(50, MILLISECONDS) that is conditions are checked after 50ms then 50ms+100ms。

csharp 复制代码
@Test
public void testAsynchronousPoll() {
    AwaitilityExample example = new AwaitilityExample();
    example.startAsyncTask();
    try {
        // Polling query, pollInterval specifies how often to poll, pollDelay specifies the delay between each poll
        Awaitility.with().pollInterval(ONE_HUNDRED_MILLISECONDS).and().with().pollDelay(50, MILLISECONDS).await("count is greater 3").until(
                new Callable<Boolean>() {
                    @Override
                    public Boolean call() throws Exception {
                        return example.isFlag();
                    }
                });
    } catch (Exception e) {
        Assertions.fail("Run exception: " + e.getMessage() + ", error: " + e.getStackTrace()[0].toString());
    }
}

3-5.Fibonacci 轮询

with().pollInterval(fibonacci(SECONDS)) 非线性轮询,按照 fibonacci 数轮询。

csharp 复制代码
@Test
public void testAsynchronousFibonacciPoll() {
    AwaitilityExample example = new AwaitilityExample();
    example.startAsyncTask();
    try {
        // Use Fibonacci numbers as the interval: 1, 1, 2, 3, 5, 8,..., default unit is milliseconds
        Awaitility.with().pollInterval(fibonacci(SECONDS)).await("count is greater 3").until(
                new Callable<Boolean>() {
                    @Override
                    public Boolean call() throws Exception {
                        return example.isFlag();
                    }
                });
    } catch (Exception e) {
        Assertions.fail("Run exception: " + e.getMessage() + ", error: " + e.getStackTrace()[0].toString());
    }
}

4.引用

相关推荐
一 乐42 分钟前
婚纱摄影网站|基于ssm + vue婚纱摄影网站系统(源码+数据库+文档)
前端·javascript·数据库·vue.js·spring boot·后端
码事漫谈2 小时前
Protocol Buffers 编码原理深度解析
后端
码事漫谈2 小时前
gRPC源码剖析:高性能RPC的实现原理与工程实践
后端
踏浪无痕3 小时前
AI 时代架构师如何有效成长?
人工智能·后端·架构
程序员小假4 小时前
我们来说一下无锁队列 Disruptor 的原理
java·后端
武子康5 小时前
大数据-209 深度理解逻辑回归(Logistic Regression)与梯度下降优化算法
大数据·后端·机器学习
maozexijr5 小时前
Rabbit MQ中@Exchange(durable = “true“) 和 @Queue(durable = “true“) 有什么区别
开发语言·后端·ruby
源码获取_wx:Fegn08955 小时前
基于 vue智慧养老院系统
开发语言·前端·javascript·vue.js·spring boot·后端·课程设计
独断万古他化5 小时前
【Spring 核心: IoC&DI】从原理到注解使用、注入方式全攻略
java·后端·spring·java-ee
毕设源码_郑学姐5 小时前
计算机毕业设计springboot基于HTML5的酒店预订管理系统 基于Spring Boot框架的HTML5酒店预订管理平台设计与实现 HTML5与Spring Boot技术驱动的酒店预订管理系统开
spring boot·后端·课程设计