前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >编写rust测试程序

编写rust测试程序

作者头像
zy010101
发布2023-04-24 10:35:31
1.2K0
发布2023-04-24 10:35:31
举报
文章被收录于专栏:程序员

编写rust测试

rust提供了编写测试的方式来让我们对程序编写测试用例。

测试函数

当使用 Cargo 创建一个 lib 类型的包时,它会为我们自动生成一个测试模块。先来创建一个 lib 类型的 adder 包。创建成功后,在 src/lib.rs 文件中可以发现如下代码:

代码语言:javascript
复制
pub fn add(left: usize, right: usize) -> usize {
    left + right
}

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

    #[test]
    fn it_works() {
        let result = add(2, 2);
        assert_eq!(result, 4);
    }
}

其中,tests 就是一个测试模块,it_works 则是测试函数,它对add函数进行了测试。测试函数需要使用 #[test] 属性进行标注。关于属性( attribute ),我们在之前的章节已经见过类似的 derive,使用它可以派生自动实现的 Debug 、Copy 等特征,同样的,使用 test 属性,我们也可以获取 Rust 提供的测试特性。

经过 test 标记的函数就可以被测试执行器发现,并进行运行。当然,在测试模块 tests 中,还可以定义非测试函数,这些函数可以用于设置环境或执行一些通用操作:例如为部分测试函数提供某个通用的功能,这种功能就可以抽象为一 个非测试函数。

执行测试

之前,对于library的package,我们是使用cargo build来构建的。对于测试而言,可以执行cargo test来执行项目中的所有测试。执行上面的

代码语言:javascript
复制
running 1 test
test tests::it_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

测试用例是分批执行的,running 1 test 表示下面的输出 test result 来自一个测试用例的运行结果。

test tests::it_works 中包含了测试用例的名称

test result: ok 中的 ok 表示测试成功通过

1 passed 代表成功通过一个测试用例(因为只有一个),0 failed : 没有测试用例失败,0 ignored 说明我们没有将任何测试函数标记为运行时可忽略,0 filtered 意味着没有对测试结果做任何过滤,

0 mesasured 代表基准测试(benchmark)的结果

还有一个很重要的点,输出中的 Doc-tests adder 代表了文档测试。我们这里没有文档,因此测试用例是0。

现在,我们来添加自己的函数以及对应的测试函数。例如:

代码语言:javascript
复制
pub fn add(left: usize, right: usize) -> usize {
    left + right
}

pub fn hello() {
    println!("hello");
}

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

    #[test]
    fn exploration() {
        let result = add(2, 2);
        assert_eq!(result, 4);
    }

    #[test]
    fn hello_test() {
        assert_eq!((), hello())
    }
}

现在执行cargo test,输出如下所示:

代码语言:javascript
复制
running 2 tests
test tests::hello_test ... ok
test tests::exploration ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

可以看到,输出的test tests中的两个测试函数的名字分别是hello_test和exploration(我们更改了刚才的it_works的名称),同时测试结果是显示2 passed。

Rust 在默认情况下会为每一个测试函数启动单独的线程去处理,当主线程 main 发现有一个测试线程死掉时,main 会将相应的测试标记为失败。事实上,多线程运行测试虽然性能高,但是存在数据竞争的风险。

失败的测试用例

下面来看一下失败的测试结果是怎么样的。

代码语言:javascript
复制
#[test]
fn another() {
    panic!("Make this test fail");
}

我们直接在test模块中加上上面这个测试函数,当它被执行的时候,会直接调用panic抛出错误。执行cargo test,结果如下所示:

代码语言:javascript
复制
running 3 tests
test tests::exploration ... ok
test tests::hello_test ... ok
test tests::another ... FAILED

failures:

---- tests::another stdout ----
thread 'tests::another' panicked at 'Make this test fail', src/lib.rs:26:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    tests::another

test result: FAILED. 2 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--lib`

可以看到之前的两个测试函数通过了,新增的another失败了,并且给出了相应的失败输出 tests::another stdout ,因此最终的结果是测试失败。

自定义失败信息

默认的失败信息在有时候并不是我们想要的,来看一个例子:

代码语言:javascript
复制
pub fn greeting(name: &str) -> String {
    format!("Hello {}!", name)
}

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

    #[test]
    fn greeting_contains_name() {
        let result = greeting("zhangsan");
        let target = "张三";
        assert!(result.contains(target), "你的问候中并没有包含目标姓名{target},你的问候是 `{result}`");
    }
}

执行cargo test测试上面的代码,输出结果如下所示:

代码语言:javascript
复制
running 1 test
test tests::greeting_contains_name ... FAILED

failures:

---- tests::greeting_contains_name stdout ----
thread 'tests::greeting_contains_name' panicked at '你的问候中并没有包含目标姓名张三,你的问候是 `Hello zhangsan!`', src/lib.rs:62:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    tests::greeting_contains_name

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--lib`

assert宏

在 Rust 中,assert 宏接受两个参数:

  1. condition:要检查的条件表达式,它的值必须是布尔型(bool)。
  2. message:可选的错误信息字符串,如果断言失败,该信息将被打印到标准输出流(stdout)中

Rust 还提供了 debug_assert 宏,它只在调试模式下检查条件,并在发布模式下忽略它。这个宏的语法与 assert 宏相同。

测试 panic

如果一个函数本来就会 panic ,而我们想要检查测试是否发生了panic。对此rust提供了 should_panic 属性注解,就和test注解一样。

代码语言:javascript
复制
#[allow(unused)]
pub struct Guess {
    value: i32,
}

impl Guess {
    pub fn new(value: i32) -> Guess {
        if value < 1 || value > 100 {
            panic!("Guess value must be between 1 and 100, got {}.", value);
        }

        Guess { value }
    }
}

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

    #[test]
    #[should_panic]
    fn greater_than_100() {
        Guess::new(200);
    }
}

这段代码执行cargo test之后输出如下所示:

代码语言:javascript
复制
running 1 test
test tests::greater_than_100 - should panic ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

可以看到测试结果是成功,这意味着它确实发生了崩溃。如果我们将代码中的Guess::new(200)改为Guess::new(20),那么should_panic测试会失败,因为测试并没有按照预期发生 panic。

虽然 panic 被成功测试到,但是如果代码发生的 panic 和我们预期的 panic 不符合呢?因为一段糟糕的代码可能会在不同的代码行生成不同的 panic。鉴于此,我们可以使用可选的参数 expected 来说明预期的 panic 长啥样。

except

代码语言:javascript
复制
impl Guess {
    pub fn new(value: i32) -> Guess {
        if value < 1 {
            panic!(
                "Guess value must be greater than or equal to 1, got {}.",
                value
            );
        } else if value > 100 {
            panic!(
                "Guess value must be less than or equal to 100, got {}.",
                value
            );
        }

        Guess { value }
    }
}

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

    #[test]
    #[should_panic(expected = "Guess value must be less than or equal to 100")]     // except
    fn greater_than_100() {
        Guess::new(200);
    }
}

这段代码会通过测试,因为通过增加了 expected ,我们成功指定了期望的 panic 信息。如果注意看,你会发现 expected 的字符串和实际 panic 的字符串可以不同,前者只需要是后者的字符串前缀即可,如果改成 #[should_panic(expected = “Guess value must be less than”)],一样可以通过测试。

测试用例的并行或顺序执行

当运行多个测试函数时,默认情况下是为每个测试都生成一个线程,然后通过主线程来等待它们的完成和结果。这种模式的优点很明显,那就是并行运行会让整体测试时间变短很多,但是有利就有弊,并行测试最大的问题就在于共享状态的修改,因为你难以控制测试的运行顺序,因此如果多个测试共享一个数据,那么对该数据的使用也将变得不可控制。例如,我们有多个测试,它们每个都会往该文件中写入一些自己的数据,最后再从文件中读取这些数据进行对比。由于所有测试都是同时运行的,当测试 A 写入数据准备读取并对比时,很有可能会被测试 B 写入新的数据,导致 A 写入的数据被覆盖,然后 A 再读取到的就是 B 写入的数据。结果 A 测试就会失败,而且这种失败还不是因为测试代码不正确导致的!解决办法也有,我们可以让每个测试写入自己独立的文件中,当然,也可以让所有测试一个接着一个顺序运行:

代码语言:javascript
复制
cargo test -- --test-threads=1

第一个–是用来分割参数到底是传给谁的。在第一个–之前的参数是传递给cargo的,而之后是传递给编译后的可执行程序的。线程数不仅仅可以指定为 1,还可以指定为 4、8,当然,想要顺序运行,就必须是 1。

测试中使println!生效

默认情况下,如果测试通过,那写入标准输出的内容是不会显示在测试结果。不过可以通过增加--show-output参数来使得成功的测试中的println可以输出。例如:

代码语言:javascript
复制
#[allow(unused)]
fn add(a:i32, b:i32) -> i32{
    println!("test output: 0000000000");
    a + b

}

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

    #[test]
    fn t1() {
        let res = add(1, 2);
        assert_eq!(res, 3);
    }


    #[test]
    fn t2() {
        let res = add(1, 2);
        assert_eq!(res, 2);
    }
}

执行cargo test,输出结果如下所示:

代码语言:javascript
复制
running 2 tests
test tests::t1 ... ok
test tests::t2 ... FAILED

failures:

---- tests::t2 stdout ----
test output: 0000000000
thread 'tests::t2' panicked at 'assertion failed: `(left == right)`
left: `3`,
right: `2`', src/lib.rs:152:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    tests::t2

test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--lib`

结果显示t2测试失败,t2调用的add函数中的println进行了输出,但是t1函数中的println输出的结果没有进行展示。如果想要成功的测试也输出println中的内容,可以使用cargo test – --show-output来执行程序。

指定运行一部分测试

有时候每次都运行全部测试是不可接受的(因为测试可能特别耗时),特别是你的工作仅仅是项目中的一部分时。

运行单个测试

这个很简单,只需要将指定的测试函数名作为参数即可,例如:

代码语言:javascript
复制
cargo test t1

通过名称来过滤测试

我们可以通过指定部分名称的方式来过滤运行相应的测试,例如上面我们有两个测试函数t1和t2,那么我们可以指定名称的一部分t,这样t1和t2就会被执行。事实上,你不仅可以使用前缀,还能使用名称中间的一部分。我们来换一个例子,上面例子中名字太短了。

代码语言:javascript
复制
#[cfg(test)]
mod tests{
    use super::*;

    #[test]
    fn add_test1() {
        let res = add(1, 2);
        assert_eq!(res, 3);
    }


    #[test]
    fn add_test2() {
        let res = add(1, 2);
        assert_eq!(res, 2);
    }
}

OK,我们更新了上面函数的名字,然后可以分别执行cargo test t1, cargo test t2, cargo test add来试一试,其分别会执行add_test1,add_test2以及全部执行。还可以通过指定模块名来过滤测试,例如:

代码语言:javascript
复制
#[cfg(test)]
mod tests{
    use super::*;

    #[test]
    fn test1() {
        let res = add(1, 2);
        assert_eq!(res, 3);
    }
}

#[cfg(test)]
mod addmodule_test{

    use super::*;

    #[test]
    fn test2() {
        let res = add(1, 2);
        assert_eq!(res, 2);
    }
}

当执行cargo test的时候,所有的测试模块都会被执行,其中的所有的测试函数都会被执行。我们可以通过指定模块名称来执行测试模块cargo test addmodulecargo test tests来分别执行addmodule测试模块和tests测试模块。

忽略部分测试

有时候,一些测试会非常耗时间,因此我们希望在 cargo test 中对它进行忽略,如果使用之前的方式,我们需要将所有需要运行的名称指定一遍,这非常麻烦,好在 Rust 允许通过 ignore 关键字来忽略特定的测试用例:

代码语言:javascript
复制
#[test]
fn it_works() {
    assert_eq!(2 + 2, 4);
}

#[test]
#[ignore]   // 使用cargo test的时候忽略该测试函数
fn expensive_test() {
    // 这里的代码需要几十秒甚至几分钟才能完成
}

当然,也可以通过cargo test -- --ignored方式运行被忽略的测试函数。

组合过滤

代码语言:javascript
复制
#[cfg(test)]
mod tests {
    use super::*;

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

    #[test]
    #[ignore]
    fn expensive_test() {
        // 这里的代码需要几十秒甚至几分钟才能完成
    }

    #[test]
    #[ignore]
    fn expensive_run() {
        // 这里的代码需要几十秒甚至几分钟才能完成
    }
}

可以通过执行cargo test run -- --ignored来运行名称中带 run 且被忽略的测试函数。也可以通过执行cargo test tests -- --ignored运行 tests 模块中的被忽略的测试函数。

更漂亮的测试输出,使用pretty_assertions库

它可以用来扩展标准库中的 assert_eq! 和 assert_ne!,例如提供彩色字体的结果对比。将其指定为[dev-dependencies] ,它将仅用于编译测试、示例和基准测试。这样cargo build不会影响编译时间!当你使用cargo add pretty_assertions的时候,默认添加pretty_assertions到[dependencies]下面,例如:

代码语言:javascript
复制
[dependencies]
pretty_assertions = "1.3.0"

需要将pretty_assertions放到[dev-dependencies]下面

代码语言:javascript
复制
[dev-dependencies]
pretty_assertions = "1.3.0"

另外,还要添加#[cfg(test)]到use语句中,如下所示:

代码语言:javascript
复制
#[cfg(test)]
use pretty_assertions::{assert_eq, assert_ne};

生成测试二进制文件

在有些时候,我们可能希望将测试与别人分享,这种情况下生成一个类似 cargo build 的可执行二进制文件是很好的选择。

事实上,在 cargo test 运行的时候,系统会自动为我们生成一个可运行测试的二进制可执行文件:

代码语言:javascript
复制
Compiling diff v0.1.13
Compiling yansi v0.5.1
Compiling pretty_assertions v1.3.0
Compiling adder v0.1.0 (/home/ubuntu/learn/rust/adder)
 Finished test [unoptimized + debuginfo] target(s) in 0.97s
  Running unittests src/lib.rs (target/debug/deps/adder-bedc2f4c9b465bb8)

这里的target/debug/deps/adder-bedc2f4c9b465bb8就是测试程序的路径和名称。可以直接执行它来进行测试。

代码语言:javascript
复制
./target/debug/deps/adder-bedc2f4c9b465bb8

条件编译 #[cfg(test)]

代码中的 #[cfg(test)] 标注可以告诉 Rust 只有在 cargo test 时才编译和运行模块 tests,其它时候当这段代码是空气即可,例如在 cargo build 时。这么做有几个好处:

  1. 节省构建代码时的编译时间
  2. 减小编译出的可执行文件的体积

其实集成测试就不需要这个标注,因为它们被放入单独的目录文件中,而单元测试是跟正常的逻辑代码在同一个文件,因此必须对其进行特殊的标注,以便 Rust 可以识别。

#[cfg(test)] 中,cfg 是配置 configuration 的缩写,它告诉 Rust :当 test 配置项存在时,才运行下面的代码,而 cargo test 在运行时,就会将 test 这个配置项传入进来,因此后面的 tests 模块会被包含进来。

单元测试

单元测试目标是测试某一个代码单元(一般都是函数),验证该单元是否能按照预期进行工作,例如测试一个 add 函数,验证当给予两个输入时,最终返回的和是否符合预期。

在 Rust 中,单元测试的惯例是将测试代码的模块跟待测试的正常代码放入同一个文件中,例如 src/lib.rs 文件中有如下代码:

代码语言:javascript
复制
pub fn add_two(a: i32) -> i32 {
    a + 2
}

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

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

add_two 是我们的项目代码,为了对它进行测试,我们在同一个文件中编写了测试模块 tests,并使用 #[cfg(test)] 进行了标注。

测试私有函数

关于私有函数能否被直接测试,编程社区里一直争论不休,甚至于部分语言可能都不支持对私有函数进行测试或者难以测试。无论你的立场如何,反正 Rust 是支持对私有函数进行测试的。

代码语言:javascript
复制
pub fn add_two(a: i32) -> i32 {
    internal_adder(a, 2)
}

fn internal_adder(a: i32, b: i32) -> i32 {
    a + b
}

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

    #[test]
    fn internal() {
        assert_eq!(4, internal_adder(2, 2));
    }
}

但是在上述代码中,我们使用 use super:😗; 将 tests 的父模块中的所有内容引入到当前作用域中,这样就可以非常简单的实现对私有函数的测试。

集成测试

与单元测试的同吃同住不同,集成测试的代码是在一个单独的目录下的。由于它们使用跟其它模块一样的方式去调用你想要测试的代码,因此只能调用通过 pub 定义的 API,这一点与单元测试有很大的不同。

如果说单元测试是对代码单元进行测试,那集成测试则是对某一个功能或者接口进行测试,因此单元测试的通过,并不意味着集成测试就能通过:局部上反映不出的问题,在全局上很可能会暴露出来。

一个标准的 Rust 项目,在它的根目录下会有一个 tests 目录。该目录就是用来存放集成测试的,Cargo 会自动来此目录下寻找集成测试文件。我们可以在该目录下创建任何文件,Cargo 会对每个文件都进行自动编译。但你需要好好的组织你的测试代码。

首先来创建一个集成测试文件 tests/integration_test.rs,tests目录需手动创建,它和src是同级目录。在该文件中写入如下内容:

代码语言:javascript
复制
use adder;

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

首先与单元测试有所不同,我们并没有创建测试模块。其次,tests 目录下的每个文件都是一个单独的包,我们需要将待测试的包引入到当前包的作用域后: use adder,才能进行测试 。因为 tests 目录本身就说明了它的特殊用途,因此我们无需再使用 #[cfg(test)] 来取悦 Cargo。后者会在运行 cargo test 时,对 tests 目录中的每个文件都进行编译运行。现在让我们来执行cargo test看一下输出

代码语言:javascript
复制
running 1 test
test tests::internal ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

    Running tests/integration_test.rs (target/debug/deps/integration_test-88b377afb4e2938c)

running 1 test
test it_adds_two ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

运行 cargo test ,可以看到上述输出。测试内容有三个部分:单元测试,集成测试和文档测试。

首先是单元测试被运行 Running unittests ,其次就是我们的主角集成测试的运行 Running tests/integration_test.rs,可以看出,集成测试的输出内容与单元测试并没有大的区别。最后运行的是文档测试 Doc-tests adder。与单元测试类似,我们可以通过指定名称的方式来运行特定的集成测试用。例如:

代码语言:javascript
复制
cargo test --test integration_test

二进制包的集成测试

目前来说,Rust 只支持对 lib 类型的包进行集成测试,对于二进制包例如 src/main.rs 是无能为力的。原因在于,我们无法在其它包中使用 use 引入二进制包,而只有 lib 类型的包才能被引入,例如 src/lib.rs。 这就是为何我们需要将代码逻辑从 src/main.rs 剥离出去放入 lib 包中,例如很多 Rust 项目中都同时有 src/main.rs 和 src/lib.rs ,前者中只保留代码的主体脉络部分,而具体的实现通通放在类似后者的 lib 包中。 这样,我们就可以对 lib 包中的具体实现进行集成测试,由于 main.rs 中的主体脉络足够简单,当集成测试通过时,意味着 main.rs 中相应的调用代码也将正常运行。

断言 assertion

在编写测试函数时,断言决定了我们的测试是通过还是失败。前文使用过assert_eq!,我们通常会使用

  • assert!, assert_eq!, assert_ne!, 它们会在所有模式下运行
  • debug_assert!, debug_assert_eq!, debug_assert_ne!, 它们只会在 Debug 模式下运行

assert_eq!

assert_eq! 宏可以用于判断两个表达式返回的值是否相等,当不相等时,当前线程会直接 panic。

因为涉及到相等比较( == )和错误信息打印,因此两个表达式的值必须实现 PartialEq 和 Debug 特征,其中所有的原生类型和大多数标准库类型都实现了这些特征,而对于你自己定义的结构体、枚举,如果想要对其进行 assert_eq! 断言,则需要实现 PartialEq 和 Debug 特征:

  • 若希望实现个性化相等比较和错误打印,则需手动实现
  • 否则可以为自定义的结构体、枚举添加 #[derive(PartialEq, Debug)] 注解,来自动派生对应的特征
代码语言:javascript
复制
let a = 1;
let b = 2;
assert_eq!(a, b, "a ({}) is not equal to b ({})", a, b);

assert_eq! 宏可以有三个参数,分别是要比较的两个值以及可选的第三个参数,用于指定 panic 时输出的信息。这个参数是一个字符串字面量,可以自定义 panic 信息。

以上特征限制对于下面即将讲解的 assert_ne! 一样有效。

assert_ne!

assert_ne!是用来判断两者的不相等性。例如:

代码语言:javascript
复制
let a = 1;
let b = 2;
assert_ne!(a, b, "a ({}) is equal to b ({})", a, b);

由于 1 不等于 2,因此这段代码不会发生panic。

assert!

assert! 用于判断传入的布尔表达式是否为 true。例如:

代码语言:javascript
复制
// 以下断言的错误信息只包含给定表达式的返回值
assert!(true);

fn some_computation() -> bool { true }

assert!(some_computation());

// 使用自定义报错信息
let x = true;
assert!(x, "x wasn't true!");

// 使用格式化的自定义报错信息
let a = 3; let b = 27;
assert!(a + b == 30, "a = {}, b = {}", a, b);

debug_assert! 系列

debug_assert!, debug_assert_eq!, debug_assert_ne! 这三个在功能上与之前讲解的版本并无区别,主要区别在于,debug_assert! 系列只能在 Debug 模式下输出。即:在cargo带有--release参数时,它们会被忽略。

基准测试 benchmark

几乎所有开发都知道,如果要测量程序的性能,就需要性能测试。

性能测试包含了两种:压力测试和基准测试。前者是针对接口 API,模拟大量用户去访问接口然后生成接口级别的性能数据;而后者是针对代码,可以用来测试某一段代码的运行速度,例如一个排序算法。rust可以使用下面两种方式来进行:

  • 官方提供的 benchmark
  • 社区实现,例如 criterion.rs

通常更推荐社区实现,它包含了更多的数据,更友好的使用方式。criterion.rs文档

参考资料

Rust语言圣经(Rust Course)

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-04-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 编写rust测试
    • 测试函数
      • 执行测试
        • 失败的测试用例
      • 自定义失败信息
        • assert宏
      • 测试 panic
        • except
      • 测试用例的并行或顺序执行
        • 测试中使println!生效
      • 指定运行一部分测试
        • 运行单个测试
        • 通过名称来过滤测试
      • 忽略部分测试
        • 组合过滤
          • 更漂亮的测试输出,使用pretty_assertions库
            • 生成测试二进制文件
              • 条件编译 #[cfg(test)]
                • 单元测试
                  • 测试私有函数
                • 集成测试
                  • 二进制包的集成测试
                    • 断言 assertion
                      • assert_eq!
                      • assert_ne!
                      • assert!
                      • debug_assert! 系列
                    • 基准测试 benchmark
                      • 参考资料
                      相关产品与服务
                      腾讯云服务器利旧
                      云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档