如何在不要求参数函数可变的情况下测试元函数?
How do I test a meta-function without requiring the parameter function to be mutable?
我写了一个函数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
保存时,我都必须使用可变引用。虽然这不会影响功能,但会混淆代码。有没有更好的方法可以达到同样的效果?
就在里面断言:
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);
}
(不确保函数被调用,这是一种权衡)
您可以使用 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
// (can panic in already borrowed, but not a problem here)
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);
}
}
我写了一个函数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
保存时,我都必须使用可变引用。虽然这不会影响功能,但会混淆代码。有没有更好的方法可以达到同样的效果?
就在里面断言:
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);
}
(不确保函数被调用,这是一种权衡)
您可以使用 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
// (can panic in already borrowed, but not a problem here)
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);
}
}