You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在assert_cmd中使用stdin实现CLI应用集成测试?

解决CLI交互式测试的两个问题

问题1:等待/检测提示信息

要检测程序输出的提示,需要手动监听子进程的stdout,直到出现目标提示字符串,确认程序进入等待输入的状态后再发送响应。

问题2:自动发送yes响应

结合异步IO控制子进程的输入输出,先启动命令,读取stdout捕获提示,再写入yes\n到stdin,最后验证执行结果。

具体实现步骤

  1. 确保依赖包含tokio(用于异步IO操作),修改Cargo.toml:
[dependencies]
assert_cmd = "2.0"
predicates = "3.0"
tokio = { version = "1.0", features = ["full"] }
  1. 修改测试代码:
use assert_cmd::Command;
use predicates::prelude::*;
use tokio::io::{AsyncBufReadExt, AsyncWriteExt};

#[tokio::test]
async fn add_test() -> Result<(), Box<dyn std::error::Error>> {
    // 启动CLI命令
    let mut cmd = Command::cargo_bin("hund")?
        .args(&["-f", "file.txt"])
        .spawn()?;

    // 获取子进程的stdout和stdin句柄
    let mut stdout = cmd.stdout.take().unwrap();
    let mut stdin = cmd.stdin.take().unwrap();

    // 循环读取stdout,直到捕获到你的提示字符串(替换成实际提示内容)
    let mut buf = String::new();
    while !buf.contains("请输入yes继续: ") {
        stdout.read_line(&mut buf).await?;
    }

    // 向stdin发送yes响应,记得加换行符
    stdin.write_all(b"yes\n").await?;
    stdin.flush().await?;

    // 等待命令执行完成,验证结果
    let output = cmd.wait_with_output().await?;
    assert!(output.status.success());
    assert!(predicate::str::contains("File modified").eval(&String::from_utf8_lossy(&output.stdout)));

    Ok(())
}

说明

  • 用tokio::test标记异步测试,因为需要异步处理子进程的IO交互
  • spawn()方法启动命令,而非直接调用assert(),这样能手动控制输入输出
  • 替换代码中的提示字符串(请输入yes继续: )为你CLI程序实际输出的提示内容
  • 如果你的CLI用std::io::stdin().read_line()读取输入,yes\n的格式是正确的,因为read_line会读取到换行符为止

内容的提问来源于stack exchange,提问作者Maria

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 15:00:21