Ich versuche einen einfacheren Unit-Test-Runner für mein Rust-Projekt zu schreiben. Ich habe eine TestFixture-Eigenschaft erstellt, die von meinen Test-Fixture-Strukturen implementiert wird, ähnlich wie in anderen Test-Frameworks von der Unit-Test-Basisklasse. Das Merkmal ist ziemlich einfach. Dies ist meine PrüfvorrichtungWie kann ich eine Funktion an einen anderen Thread senden?
pub trait TestFixture {
fn setup(&mut self) ->() {}
fn teardown(&mut self) ->() {}
fn before_each(&mut self) ->() {}
fn after_each(&mut self) ->() {}
fn tests(&mut self) -> Vec<Box<Fn(&mut Self)>>
where Self: Sized {
Vec::new()
}
}
Funktion My Testlauf ist wie
folgtpub fn test_fixture_runner<T: TestFixture>(fixture: &mut T) {
fixture.setup();
let _r = fixture.tests().iter().map(|t| {
let handle = thread::spawn(move || {
fixture.before_each();
t(fixture);
fixture.after_each();
});
if let Err(_) = handle.join() {
println!("Test failed!")
}
});
fixture.teardown();
}
ich den Fehler
src/tests.rs:73:22: 73:35 error: the trait `core::marker::Send` is not implemented for the type `T` [E0277]
src/tests.rs:73 let handle = thread::spawn(move || {
^~~~~~~~~~~~~
note: in expansion of closure expansion
src/tests.rs:69:41: 84:6 note: expansion site
src/tests.rs:73:22: 73:35 note: `T` cannot be sent between threads safely
src/tests.rs:73 let handle = thread::spawn(move || {
^~~~~~~~~~~~~
note: in expansion of closure expansion
src/tests.rs:69:41: 84:6 note: expansion site
src/tests.rs:73:22: 73:35 error: the trait `core::marker::Sync` is not implemented for the type `for<'r> core::ops::Fn(&'r mut T)` [E0277]
src/tests.rs:73 let handle = thread::spawn(move || {
^~~~~~~~~~~~~
note: in expansion of closure expansion
src/tests.rs:69:41: 84:6 note: expansion site
src/tests.rs:73:22: 73:35 note: `for<'r> core::ops::Fn(&'r mut T)` cannot be shared between threads safely
src/tests.rs:73 let handle = thread::spawn(move || {
^~~~~~~~~~~~~
note: in expansion of closure expansion
Ich habe versucht, das Hinzufügen Arcs um die Typen auf den Thread gesendet werden , kein Würfel, der gleiche Fehler.
pub fn test_fixture_runner<T: TestFixture>(fixture: &mut T) {
fixture.setup();
let fix_arc = Arc::new(Mutex::new(fixture));
let _r = fixture.tests().iter().map(|t| {
let test_arc = Arc::new(Mutex::new(t));
let fix_arc_clone = fix_arc.clone();
let test_arc_clone = test_arc.clone();
let handle = thread::spawn(move || {
let thread_test = test_arc_clone.lock().unwrap();
let thread_fix = fix_arc_clone.lock().unwrap();
(*thread_fix).before_each();
(*thread_test)(*thread_fix);
(*thread_fix).after_each();
});
if let Err(_) = handle.join() {
println!("Test failed!")
}
});
fixture.teardown();
}
Eine Probe Prüfvorrichtung wäre so etwas wie
struct BuiltinTests {
pwd: PathBuf
}
impl TestFixture for BuiltinTests {
fn setup(&mut self) {
let mut pwd = env::temp_dir();
pwd.push("pwd");
fs::create_dir(&pwd);
self.pwd = pwd;
}
fn teardown(&mut self) {
fs::remove_dir(&self.pwd);
}
fn tests(&mut self) -> Vec<Box<Fn(&mut BuiltinTests)>> {
vec![Box::new(BuiltinTests::cd_with_no_args)]
}
}
impl BuiltinTests {
fn new() -> BuiltinTests {
BuiltinTests {
pwd: PathBuf::new()
}
}
}
fn cd_with_no_args(&mut self) {
let home = String::from("/");
env::set_var("HOME", &home);
let mut cd = Cd::new();
cd.run(&[]);
assert_eq!(env::var("PWD"), Ok(home));
}
#[test]
fn cd_tests() {
let mut builtin_tests = BuiltinTests::new();
test_fixture_runner(&mut builtin_tests);
}
Meine ganze Absicht der Verwendung von Threads ist isoliert von den Testläufer sein. Wenn ein Test eine Behauptung nicht besteht, verursacht es eine Panik, die den Läufer tötet. Danke für irgendeinen Einblick, ich bin bereit, mein Design zu ändern, wenn das das Panikproblem beheben wird.
Wenn Sie sich nicht für Threading interessieren, sondern nur das Panic-Capturen möchten, können Sie ['std :: thread :: catch_panic'] verwenden (https://doc.rust-lang.org/nightly/std /thread/fn.catch_panic.html) –