我如何在不要求参数函数可变的情况下测试元函数?

问题描述 投票:0回答:2

我已经编写了将函数作为参数的函数save

fn save(method:&dyn Fn(&'static str)) {
    method("Hello world");
}

fn print(string:&'static str) {
    println!("{}", string);
}

fn main() {
    save(&print)
}

这很好!但是我现在要测试save。我认为最好的方法是使用FnMut

fn save(method: &mut dyn FnMut(&'static str)) {
    method("Hello world");
}

fn print(string: &'static str) {
    println!("{}", string);
}

fn main() {
    save(&mut print)
}

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

    #[test]
    fn save_test() {
        let actual = {
            let mut actual = String::new();
            let mut method = |string: &'static str| {
                actual = format!("{}{}", actual, string);
            };
            save(&mut method);
            save(&mut method);
            actual
        };
        let expected = "Hello worldHello world".to_string();

        assert_eq!(actual, expected);
    }
}

这仍然可以完成我想要的一切!但是现在call保存时,我必须使用可变引用。虽然这不会影响功能,但会混淆代码。有没有更好的方法来达到相同的结果?

testing rust automated-tests higher-order-functions
2个回答
1
投票

只需在内部声明:

fn save(method: impl Fn(&'static str)) {
    method("Hello world");
}

#[test]
fn save_test() {
    let check = |result| {
        assert_eq!(result, "Hello world");
    };
    save(check);
    save(check);
}

1
投票

您可以使用RefCell获得内部可变性,从而允许您通过共享引用来可变变量。非常适合测试以下内容:

RefCell

#[cfg(test)] mod tests { use std::cell::RefCell; use super::*; #[test] fn save_test() { let actual = { // wrap "actual" in a RefCell, which allows for interior mutability let actual = RefCell::new(String::new()); let method = |string: &'static str| { // mutably borrow the string at runtime let mut actual = actual.borrow_mut(); // append string (equivalent to your format!() but can be more // efficient) actual.push_str(string); }; save(&method); save(&method); // move string out of RefCell actual.into_inner() }; let expected = "Hello worldHello world".to_string(); assert_eq!(actual, expected); } }

© www.soinside.com 2019 - 2024. All rights reserved.