有没有办法检测是否正在从 Rust 的测试中调用代码? [英] Is there a way of detecting whether code is being called from tests in Rust?

查看:50
本文介绍了有没有办法检测是否正在从 Rust 的测试中调用代码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望能够在我的代码本身中检查它是否正在从测试中运行.这样做是理想的,例如,与测试数据库、Web 服务等交互.一个简单的 bool 就足够了.

I'd like to be able to check within my code itself whether or not it is running from a test. It would be ideal to do this, for example, to interface with test databases, web services, etc. A simple bool would suffice.

Rust 是否有用于此的现有 API?

Does Rust have an existing API for this?

推荐答案

测试的运行时检测

运行测试时没有设置全局变量.您可以添加一个,但要正确处理非常复杂.这个例子没有完全正确:

Runtime detection of tests

There's no global variable that is set when running tests. You could add one, but it's pretty complicated to get it right. This example does not get it completely right:

use std::cell::Cell;

thread_local! {
    pub static IS_TESTING: Cell<bool> = Cell::new(false);
}

fn my_code() -> u8 {
    if IS_TESTING.with(|t| t.get()) {
        0
    } else {
        42
    }
}

#[test]
fn one() {
    IS_TESTING.with(|t| t.set(true));

    assert_eq!(0, my_code());

    IS_TESTING.with(|t| t.set(false));
}

要正确执行此操作,您需要处理以下事项:

To do this correctly, you need to handle a few things:

  1. 测试是在多线程环境中运行的,因此您需要确保自己处理好.
  2. 如果您的代码产生线程,则使用线程本地可能是不正确的,因为变量不会传递给它们.
  3. 即使测试因断言失败而提前中止,您也需要确保将标志设置回 false.
  1. Tests are run in a multithreaded environment, so you need to make sure that you handle that.
  2. Using a thread-local is probably incorrect if your code spawns new threads, as the variable won't carry over to them.
  3. You need to make sure to set the flag back to false even when the test aborts early due to an assertion failure.

测试的编译时间检测

更有可能的是,您想要检测您是否正在编译进行测试.这要简单得多,而且您可能已经在使用相同的技术来有条件地自行编译测试:

Compile time detection of tests

More likely, what you want is to detect if you are compiling for tests. This is much simpler and you are probably already using the same technique to conditionally compile your tests themselves:

fn my_code() -> u8 {
    if cfg!(test) {
        0
    } else {
        42
    }
}

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

    #[test]
    fn one() {
        assert_eq!(0, my_code());
    }
}

依赖注入更好

在编辑上,从代码质量的角度来看,运行时或编译时检测是一个坏主意.与其用大量条件检查乱扔代码,这会使代码复杂化甚至减慢代码速度,不如引入依赖注入:

trait ValueSource {
    fn value(&self) -> u8;
}

struct ProductionSource;
impl ValueSource for ProductionSource {
    fn value(&self) -> u8 {
        42
    }
}

fn my_code<S>(source: S) -> u8
where
    S: ValueSource,
{
    source.value()
}

#[cfg(test)]
mod test {
    use super::*;
    struct TestSource(u8);
    impl ValueSource for TestSource {
        fn value(&self) -> u8 {
            self.0
        }
    }

    #[test]
    fn one() {
        let src = TestSource(99);
        assert_eq!(99, my_code(src));
    }
}

这会将相关细节集中到一个对象中,编译器会对调用进行单态化,从而生成优化的代码.

This will concentrate related details into one object and the compiler monomorphizes the calls, producing optimized code.

这篇关于有没有办法检测是否正在从 Rust 的测试中调用代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆