【问题标题】:How can I test stdin and stdout?如何测试标准输入和标准输出?
【发布时间】:2015-02-06 16:17:11
【问题描述】:

我想编写一个提示函数,它将传入的字符串发送到标准输出,然后返回它从标准输入读取的字符串。我该如何测试它?

这是一个函数的例子:

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

这是我的测试尝试

#[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
}

【问题讨论】:

    标签: testing rust


    【解决方案1】:

    使用依赖注入。将它与泛型和单态结合起来,您不会损失任何性能:

    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 是发生故障的常见位置。


    这可以从函数扩展到方法

    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);
    }
    

    【讨论】:

    • 您能评论一下为什么这不会失去性能吗?是不是println! 只会打电话给writeln!(io::stdout(),...
    • @FrankMeulenaar println! 最终使用标准输出,是的,但不完全是那种方式。换个问题——为什么失去性能?
    猜你喜欢
    • 2014-08-05
    • 1970-01-01
    • 2021-10-20
    • 2013-09-18
    • 2013-06-13
    • 2012-03-16
    • 1970-01-01
    • 1970-01-01
    • 2014-07-22
    相关资源
    最近更新 更多