【问题标题】:How does one write function stubs for testing Rust modules?如何编写函数存根来测试 Rust 模块?
【发布时间】:2021-06-10 16:25:39
【问题描述】:

在我过去测试 C 代码的经验中,函数存根几乎是强制性的。在我的安全关键工作中,我通常需要测试所有内容——甚至是抽象函数,这些函数只是简单地调用特定于构建的实现参数作为参数,返回作为返回。

我在 Rust 中搜索了被测模块外部的存根函数的方法,但找不到解决方案。

有几个用于 trait-mocking 的库,但我对这个主题的阅读很少表明它不是我想要的。

另一个建议是,我测试的调用外部函数的函数会传入这些函数,从而允许测试简单地传递所需的伪存根函数。就传入和传出伪存根的数据而言,这似乎非常不灵活,并导致代码在每一层都被函数引用参数污染——当被测函数除了一个操作函数之外永远不会调用任何东西时,这是非常不可取的存根。您正在编写操作代码以适应测试系统的限制。

这似乎非常基本。肯定有办法用 Rust 和 Cargo 存根外部函数吗?

【问题讨论】:

  • 这能回答你的问题吗? How to mock external dependencies in tests?
  • “肯定有办法用 Rust 和 Cargo 存根外部函数吗?” 简短的回答是“不是不使用一些宏魔法,那里的一些板条箱可能会提供但是YMMV”。 “导致代码被每个级别的函数引用参数污染”如果您使用标准实现为测试模块创建类型别名,则不完全正确。
  • 您好,感谢您的回复。我不确定我是否遵循第二个。不过,第一个正是我想要避免的——使代码更复杂,以便对其进行测试。
  • 如果无法通过特征注入依赖项,您可以使用conditional compilation 使您的use 语句在测试环境中导入不同的内容。它不是很灵活,但这可能是您想要的吗?

标签: unit-testing rust integration-testing stub


【解决方案1】:

您可以尝试使用像 mockall 这样的模拟板条箱,我认为它更完整,但仍然可能需要一些时间来适应。
如果没有模拟板条箱,我建议在另一个中模拟特征/结构,然后使用 #[cfg(test)] 属性将其引入范围。当然,这将强制您使用 `#[cfg(not(test))] 注释 production use 语句。例如:

如果您使用来自external-crate 的外部结构ExternalStruct 和方法external_method,您会得到类似的结果:

文件real_code.rs

#[cfg(not(test))]
use external-crate::ExternalStruct;
#[cfg(test)]
use test_mocks::ExternalStruct;

fn my_function() {
   //...
   ExternalTrait::external_method();
}

#[test]
fn test_my_function(){
   my_function();
}

文件test_mocks.rs:

pub Struct ExternalStruct {}

impl ExternalStruct {
   pub fn external_method() {
      //desired mock behaviour
   }
}

在运行测试时,将使用 test_mocks 中的 ExternalStruct,否则将使用真正的依赖项。

【讨论】:

    猜你喜欢
    • 2016-07-02
    • 2013-11-04
    • 1970-01-01
    • 1970-01-01
    • 2018-01-28
    • 1970-01-01
    • 1970-01-01
    • 2021-09-25
    • 1970-01-01
    相关资源
    最近更新 更多