pub struct Shared<T> { /* private fields */ }
shared
only.Expand description
Wrapper around Mock
state that provides cross-thread synchronization.
This type rarely needs to be used directly; #[derive(Mock)]
macro with a #[mock(shared)]
attribute on the container will set it up automatically.
Unlike ThreadLocal
wrapper, this one shares the state across
threads, with state synchronization via reentrant mutexes (to allow for recursive calls).
Setting the state is synchronized via a mutex as well: while one test thread
has a MockGuard
, other tests attempting to set the state will block.
Pitfalls
Tests that do not set the mock state (i.e., ones that want to deal with real implementations) can still observe a mock impl “spilled” from another test. This is most probably not what you want, and there are ways to deal with this issue:
- Run tests one at a time via
cargo test -j 1
. - Call
Mock::lock()
at the beginning of the relevant tests.
Examples
use mimicry::{mock, CheckRealCall, Mock};
#[derive(Debug, Default, Mock)]
#[mock(shared)]
// ^ use the `Shared` wrapper instead of the default thread-local one
struct MockState {
counter: AtomicU32,
}
impl MockState {
fn answer(&self) -> u32 {
self.counter.fetch_add(1, Ordering::Relaxed)
}
}
// Mocked function.
#[mock(using = "MockState")]
fn answer() -> u32 { 42 }
#[test]
fn some_test() {
// Sets the mock state until `mock_guard` is dropped.
let mock_guard = MockState::default().set_as_mock();
// Call mocked functions (maybe, indirectly). Calls may originate
// from different threads.
let threads: Vec<_> = (0..5).map(|_| thread::spawn(answer)).collect();
let answers: HashSet<_> = threads
.into_iter()
.map(|handle| handle.join().unwrap())
.collect();
assert_eq!(answers, HashSet::from_iter(0..5));
let state = mock_guard.into_inner();
// Can check the state here...
assert_eq!(state.counter.into_inner(), 5);
}
Trait Implementations
Auto Trait Implementations
impl<T> !RefUnwindSafe for Shared<T>
impl<T> Send for Shared<T> where
T: Send,
impl<T> Sync for Shared<T> where
T: Send,
impl<T> Unpin for Shared<T> where
T: Unpin,
impl<T> UnwindSafe for Shared<T> where
T: UnwindSafe,
Blanket Implementations
sourceimpl<T> BorrowMut<T> for T where
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
const: unstable · sourcefn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more