#test-cases #case #unit-testing #test

simple_test_case

一个用于编写参数化测试的骨架属性宏

3 个稳定版本

1.2.0 2023年7月20日
1.1.0 2022年2月1日
1.0.0 2022年1月29日

#618测试

Download history 70/week @ 2024-04-22 27/week @ 2024-04-29 43/week @ 2024-05-06 116/week @ 2024-05-13 35/week @ 2024-05-20 149/week @ 2024-05-27 116/week @ 2024-06-03 102/week @ 2024-06-10 311/week @ 2024-06-17 180/week @ 2024-06-24 80/week @ 2024-07-01 115/week @ 2024-07-08 133/week @ 2024-07-15 114/week @ 2024-07-22 86/week @ 2024-07-29 96/week @ 2024-08-05

432 次每月下载
用于 2 crates

MIT 许可协议

25KB
265

测试辅助函数应该是简单的。

你不希望担心测试套件中的错误或意外行为导致测试无声地通过。因此,simple_test_case 的目标是尽量减少编写参数化测试的模板代码,而不做更多。

test_case 属性宏会为你生成多个测试函数,这些函数通过提供的输入进行参数化。你仍然需要提供 #[test] 属性(或类似 #[tokio::test] 的替代品)和所有测试用例必须在你希望应用的任何其他属性宏之前提供。

就是这样。

没有对自定义断言、固定值等提供额外的支持。但是,如果你想或需要更复杂的测试设置,只要遵循以下建议,额外的属性宏应该可以很好地与 simple_test_case 一起使用。

使用方法

有效

这里,#[test] 属性在所有 test_case 实例之后提供。这将有效。

use simple_test_case::test_case;

fn double(n: usize) -> usize {
    n * 2
}

#[test_case(1, 2; "case 1")]
#[test_case(3, 6; "case 2")]
#[test]
fn double_test(n: usize, double: usize) {
    assert_eq!(double(n), double)
}

无效

这里,#[test] 属性在所有 test_case 实例之前提供。这将导致编译器抱怨用作测试的函数不允许有任何参数。

use simple_test_case::test_case;

fn double(n: usize) -> usize {
    n * 2
}

#[test]
#[test_case(1, 2; "case 1")]
#[test_case(3, 6; "case 2")]
fn double_test(n: usize, double: usize) {
    assert_eq!(double(n), double)
}

其他属性

test_case 保留其下所有属性,并将它们转发给生成的单个测试函数。以下是一个示例,标准库中的 should_panic 属性正如所示一样工作得很好(请确保首先按上述描述提供您的测试用例)

use simple_test_case::test_case;

#[test_case(1, 2; "case 1")]
#[test_case(3, 6; "case 2")]
#[test]
#[should_panic(expected = "this works")]
fn panic_test(n: usize, double: usize) {
    assert_eq!(double(a), b);
    panic!("this works")
}

异步测试

异步测试与其他属性支持的方式相同:首先添加您的测试用例,然后在下面应用您选择的异步测试宏。

use simple_test_case::test_case;

async fn async_double(n: usize) -> usize {
    n * 2
}

#[test_case(1, 2; "case 1")]
#[test_case(3, 6; "case 2")]
#[tokio::test]
async fn double_test(n: usize, double: usize) {
    assert_eq!(double(n).await, double)
}

它是如何工作的?

建议您阅读宏本身的源代码(宏及其相关辅助函数的代码少于150行),但基本思路如下

  • 收集所有 test_case(或 simple_test_case::test_case)属性,每个属性将一组函数参数映射到测试用例名称。
  • 对于每个测试用例,创建原始测试函数的副本,并将函数参数替换为函数体顶部的显式变量绑定。
  • 将每个用例写入一个新模块中的单独测试,该模块的名称使用原始测试函数名称。

您可以使用 cargo expand 来查看生成的测试示例,如下所示(使用 examples 目录中提供的示例)

$ cargo expand --example=expand_me --tests
  Compiling simple_test_case v0.1.0 (/home/innes/repos/personal/simple_test_case)
   Finished test [unoptimized + debuginfo] target(s) in 0.12s
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use simple_test_case::test_case;
mod example {
    #[allow(unused_imports)]
    use super::*;
    extern crate test;
    #[cfg(test)]
    #[rustc_test_marker]
    pub const small_example: test::TestDescAndFn = test::TestDescAndFn {
        desc: test::TestDesc {
            name: test::StaticTestName("example::small_example"),
            ignore: false,
            allow_fail: false,
            compile_fail: false,
            no_run: false,
            should_panic: test::ShouldPanic::No,
            test_type: test::TestType::Unknown,
        },
        testfn: test::StaticTestFn(|| test::assert_test_result(small_example())),
    };
    fn small_example() {
        let a: usize = 1;
        let b: usize = 2;
        if !(a < b) {
            ::core::panicking::panic("assertion failed: a < b")
        }
    }
    extern crate test;
    #[cfg(test)]
    #[rustc_test_marker]
    pub const large_example: test::TestDescAndFn = test::TestDescAndFn {
        desc: test::TestDesc {
            name: test::StaticTestName("example::large_example"),
            ignore: false,
            allow_fail: false,
            compile_fail: false,
            no_run: false,
            should_panic: test::ShouldPanic::No,
            test_type: test::TestType::Unknown,
        },
        testfn: test::StaticTestFn(|| test::assert_test_result(large_example())),
    };
    fn large_example() {
        let a: usize = 100;
        let b: usize = 200;
        if !(a < b) {
            ::core::panicking::panic("assertion failed: a < b")
        }
    }
}
#[allow(dead_code)]
fn main() {}
#[rustc_main]
pub fn main() -> () {
    extern crate test;
    test::test_main_static(&[&small_example, &large_example])
}

依赖项

~280–730KB
~17K SLoC