我想编写一个提示函数,将传入的字符串发送到stdout,然后返回从stdin读取的字符串.我该怎么测试呢?

下面是该函数的一个示例:

fn prompt(question: String) -> String {
    let mut stdin = BufferedReader::new(stdin());
    print!("{}", question);
    match stdin.read_line() {
        Ok(line) => line,
        Err(e)   => panic!(e),
    }
}

这是我的测试try

#[test]
fn try_to_test_stdout() {
    let writer: Vec<u8> = vec![];
    set_stdout(Box::new(writer));
    print!("testing");
// `writer` is now gone, can't check to see if "testing" was sent
}

推荐答案

使用依赖注入.将其与泛型和单态相结合,不会损失任何性能:

use std::io::{self, BufRead, Write};

fn prompt<R, W>(mut reader: R, mut writer: W, question: &str) -> String
where
    R: BufRead,
    W: Write,
{
    write!(&mut writer, "{}", question).expect("Unable to write");
    let mut s = String::new();
    reader.read_line(&mut s).expect("Unable to read");
    s
}

#[test]
fn test_with_in_memory() {
    let input = b"I'm George";
    let mut output = Vec::new();

    let answer = prompt(&input[..], &mut output, "Who goes there?");

    let output = String::from_utf8(output).expect("Not UTF-8");

    assert_eq!("Who goes there?", output);
    assert_eq!("I'm George", answer);
}

fn main() {
    let stdio = io::stdin();
    let input = stdio.lock();

    let output = io::stdout();

    let answer = prompt(input, output, "Who goes there?");
    println!("was: {}", answer);
}

在许多情况下,您可能希望将错误传播回调用方,而不是使用expect,因为IO是发生故障的常见位置.


这可以从functions扩展到methods:

use std::io::{self, BufRead, Write};

struct Quizzer<R, W> {
    reader: R,
    writer: W,
}

impl<R, W> Quizzer<R, W>
where
    R: BufRead,
    W: Write,
{
    fn prompt(&mut self, question: &str) -> String {
        write!(&mut self.writer, "{}", question).expect("Unable to write");
        let mut s = String::new();
        self.reader.read_line(&mut s).expect("Unable to read");
        s
    }
}

#[test]
fn test_with_in_memory() {
    let input = b"I'm George";
    let mut output = Vec::new();

    let answer = {
        let mut quizzer = Quizzer {
            reader: &input[..],
            writer: &mut output,
        };

        quizzer.prompt("Who goes there?")
    };

    let output = String::from_utf8(output).expect("Not UTF-8");

    assert_eq!("Who goes there?", output);
    assert_eq!("I'm George", answer);
}

fn main() {
    let stdio = io::stdin();
    let input = stdio.lock();

    let output = io::stdout();

    let mut quizzer = Quizzer {
        reader: input,
        writer: output,
    };

    let answer = quizzer.prompt("Who goes there?");
    println!("was: {}", answer);
}

Rust相关问答推荐

编译项目期间使用Cargo生成时出现rustc错误

Rust函数的返回值不能引用局部变量或临时变量

Cargo.toml:如何有条件地启用依赖项功能?

为什么将易错函数的泛型结果作为泛型参数传递 infer ()?不应该是暧昧的吗?

要求类型参数有特定的大小?

如何在Rust中使用Serde创建一个自定义的反序列化器来处理带有内部标记的枚举

简单 TCP 服务器的连接由对等重置错误,mio 负载较小

如何在 Emacs Elisp 中获得类似格式化的 LSP?

仅当函数写为闭包时才会出现生命周期错误

为什么我不能克隆可克隆构造函数的Vec?

如何将 Rust 中的树状 struct 展平为 Vec<&mut ...>?

如何在 Rust 中创建最后一个元素是可变长度数组的 struct ?

为什么基于 clap::Parser 读取的大量数字进行计算比硬编码该数字时慢?

用逗号分隔字符串,但在标记中使用逗号

Abortable:悬而未决的期货?

`if let` 只是另一种编写其他 `if` 语句的方式吗?

编写 TOML 文件以反序列化为 struct 中的枚举

为什么我不能为 Display+Debug 的泛型类型实现 std::error::Error 但有一个不是泛型参数的类型?

基于名称是否存在的条件编译

Rust:为什么在 struct 中borrow 引用会borrow 整个 struct?