-
Notifications
You must be signed in to change notification settings - Fork 79
Description
I am trying to dependency inject a mocked client wrapper using a threadsafe container, Arc<Mutex<Box<dyn MyTrait>>>, such that in the test environment, I can create an instance of the mocked client wrapper and pass a clone of it back to the unit under test, similar to this:
let mut client = MockMyTrait::default();
// set expectations
let amb_client = Arc::new(Mutex::new(Box::new(client) as Box<dyn MyTrait>));
let unit = Unit::new(amb_client.clone());The trait is defined like this:
#[cfg_attr(test, automock)]
trait MyTrait: Any + Send + Sync {}The trouble is that now in the test, if I want to change the client's expectations, call checkpoint, etc., I need to lock the mutex and downcast the trait to the concrete type.
Initially I tried the following -- it compiles, but it never successfully coerced the type:
let mut guard= amb_client.lock().unwrap();
let boxed_trait: &mut Box<dyn MyTrait> = &mut *guard;
if let Some(concrete_box_ref) = boxed_trait.as_any_mut().downcast_mut::<MockMyTrait>() {
// do something with concrete ref
} else {
panic!("Should have been able to cast it...");
}Some suggestions online were to update the trait to include as_any and make the cast be different (like, guard.as_mut().as_any_mut().downcast_mut::<MockMyTrait>():
trait MyTrait: Any + Send + Sync {
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
struct DefaultMyTrait {}
impl MyTrait for DefaultMyTrait {
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}At this point, compilation fails:
error[E0277]: `(dyn std::any::Any + 'static)` cannot be shared between threads safely
--> my/work/file.rs:67:7
|
67 | trait MyTrait: Any + Send + Sync {
| ^^^^^^^ `(dyn std::any::Any + 'static)` cannot be shared between threads safely
|
= help: the trait `std::marker::Sync` is not implemented for `(dyn std::any::Any + 'static)`, which is required by `MockMyTrait: std::marker::Sync`
= note: required for `Unique<(dyn std::any::Any + 'static)>` to implement `std::marker::Sync`
It then unpacks several notes explaining Sync, etc. are required for various reasons that ultimately make many references to the automock attribute and things that it requires related to expectations, etc.
My mockall version is 0.13.1.
I've tried all this without mockall/automock being applied to the trait. It seems to very specifically be the macro.
Is there some better way to define/declare this all out so that automock produces a mock of a trait that can be downcast?