关闭

Rust中文翻译16

标签: rust编程语言testing测试
708人阅读 评论(0) 收藏 举报
分类:
Page 75

Program testing can be a very effective way to show the presence of bugs, but it is hopelessly inadequate for showing their absence. --Edsger W. Dijkstra

我们来讨论一下如何测试Rust代码.我们不会讨论如何正确的测试Rust代码.有很多正确的或错误的测试代码的思想.他们都是用了同样的基本工具,我们会向你展示如何使用它们.

4.2.1 test属性(attribute)
最简单的定义,一个Rust的测试就是一个被test属性标记的方法.让我们用Cargo来创建一个新的工程.

$cargo new adder
$cd adder

Cargo会自动帮你创建一个简单的测试例子,当你创建一个新的工程的时候.下面就是src/lib.rs的内容:

#[test]
fn it_works() {
}

注意这个#[test].这个属性说明它是一个测试函数.它现在没有函数体.但是足够通过测试了!我们可以使用cargo test来运行:


Page 76

Cargo编译了我们的代码并且运行.这里有两类输出:一类是我们写的测试,另一类是文档测试.我们会稍后讨论文档测试,现在来看看这个:

test it_works ... ok

注意it_works.它来自于我们的函数:

fn it_works() {

我们还得到了一个结论行:

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured

那么为什么我们什么都没做就可以通过测试?任何没有panic!的测试都将通过测试,任何panic!的测试都将不通过测试.我们来让测试失败:

#[test]
fn it_works() {
    assert!(false);
}

assert!是一个宏,带有一个参数:如果参数是true,什么都不发生.如果参数是false,它就panic!.再运行一次:



Page 77

Rust指出我们的测试失败了:

test it_works ... FAILED

可以在如下行显示出来:

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured

我们还得到了一个非零的状态码:

$echo $?
101

如果你想把cargo集成到其他工具中这个状态码就派上用场了.
我们可以修改我们的测试,通过添加另一个属性:should_panic:

#[test]
#[should_panic]
fn it_works() {
    assert!(false);
}

这次我们的测试如果panic了就会通过!如果完成了就不会通过.试一下:


Rust提供另一个宏,assert_eq!,它会比较两个参数是否相等:
#[test]
#[should_panic]
fn it_works() {
    assert_eq!("Hello", "world");
}

这个测试是否可以通过呢?因为有should_panic属性,它会通过测试:


should_panic测试是很脆弱的,它很难保证一些非预期的原因不会导致测试失败.为此,有另一个可选参数加入should_panic属性中.测试会保证失败信息中包含了参数中提供的字符串.一个更安全的版本如下:
#[test]
#[should_panic(expected = "assetion failed")]
fn it_works() {
    assert_eq!("Hello", "world");
}

上述都是基础!我们来写一个真正的测试:
pub fn add_two(a: i32) -> i32 {
    a + 2
}

#[test]
fn it_works() {
    assert_eq!(4, add_two(2));
}

这是一个非常平常的assert_eq!应用:调用一个函数,传递参数,然后比较它和预期输出值.

Page 79

4.2.2 tests模块

我们上述的例子有一个不太常用的问题:缺少tests模块.常用的方法是这样:
pub fb add_two(a: i32) -> i32 {
    a + 2
}

#[cfg(test)]
mod tests {
    use super::add_two;

    #[test]
    fn it_works() {
        assert_eq!(4, add_two(2));
    }
}

这里有一些改动.第一就是引入了一个tests模块,带有属性cfg.这个模块让我们把测试分组,并且可以定义一些帮助方法,这些方法不会成为我们的crate的一部分.cfg属性仅仅编译我们的测试方法,如果我们只运行测试的话.这可以节约编译时间,同时确保我们的测试不在我们常规的编译中.

第二点是使用了use声明.因为我们在一个内部模块中,我们需要把我们的代码带入到作用域中.如果你使用了一个很大的模块可能这一点会很麻烦,这是glob属性的的常规用法.让我们修改代码:


注意不同的use行.我们来运行一下:

工作正常!
流行的惯例是使用tests模块来是我们的测试"单元化".任何测试函数都可以这样使用.那么"集成化"测试怎么办呢?为此,我们还有测试目录.

4.2.3 测试目录(tests directory)

为了写一个集成测试,我们需要一个tests目录,这样写tests/lib.rs文件:
extern crate adder;



看起来和之前的测试很像,但是有一点而不一样.我们在顶部有一个extern crate adder.那是因为tests目录下的测试是一个独立的crate,所以我们需要引入我们的库.tests也是我们写集成测试最合适的地方:他们使用这个库就像其他使用者一样.

运行一下:


现在我们有3个部分: 之前的和新的.
测试目录就讲这么多.测试模块在这里不是必须的.
最后我们来讲一下第三部分:文档测试.
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:34588次
    • 积分:712
    • 等级:
    • 排名:千里之外
    • 原创:4篇
    • 转载:0篇
    • 译文:33篇
    • 评论:13条
    文章分类
    最新评论