pub struct Answers<V, Ctx = ()> { /* private fields */ }
Expand description
Answers for a function call.
Answers
are similar to an Iterator
, but with some additional functionality:
- Response can be based on a certain context (the second type param) provided to
Self::next_for()
. - The provided contexts are recorded for each call and then can be retrieved using
Self::take_calls()
. This can be used to verify calls.
The intended usage of Answers
is as an element of Mock
state
used in one or more mock methods.
Examples
let mut answers: Answers<usize> = Answers::from_values([1, 3, 5]);
let value: usize = answers.next_for(());
assert_eq!(value, 1);
assert_eq!(answers.next_for(()), 3);
assert_eq!(answers.take_calls().len(), 2);
Context-dependent Answers
:
let mut counter = 0;
let mut answers = Answers::from_fn(move |s: &String| {
if counter == 0 && s == "test" {
counter += 1;
42
} else {
s.len()
}
});
assert_eq!(answers.next_for("test".into()), 42);
assert_eq!(answers.next_for("??".into()), 2);
assert_eq!(answers.next_for("test".into()), 4);
let calls = answers.take_calls();
assert_eq!(calls, ["test", "??", "test"]);
Channels
Basic usage of Answers::channel()
:
use mimicry::Answers;
let (mut answers, mut sx) = Answers::channel();
// `rx` can be placed in the mock state
sx.send(42).scope(|| {
// Realistically, here you would call something that uses
// the mock, possibly with indirection.
assert_eq!(answers.next_for(()), 42);
});
Async scope wrapper is also available:
let (mut answers, mut sx) = Answers::channel();
let future = sx.send(42).async_scope(async {
assert_eq!(answers.next_for(()), 42);
});
future.await;
More advanced usage with explicit guard handling:
let (mut answers, mut sx) = Answers::channel();
let guard: AnswersGuard<_> = sx.send_all([0, 1, 2, 0, 1]);
for i in 0..4 {
assert_eq!(answers.next_for(i), i % 3);
}
guard.discard(); // ignore the remaining answer
If not all answers were used when a guard is dropped, it panics:
let (mut answers, mut sx) = Answers::channel();
sx.send_all([0, 1]).scope(|| {
assert_eq!(answers.next_for(()), 0);
// The code under test should make another call to the mock,
// but it does not.
});
Functional values
To deal with more complex cases, Answers
can contain functional values.
#[mock(using = "SimpleMock::mock_fn")]
fn tested_fn(s: &str, start: usize) -> &str {
&s[start..]
}
type StrFn = fn(&str) -> &str;
#[derive(Mock)]
#[mock(mut)]
struct SimpleMock {
str_fns: Answers<StrFn, (String, usize)>,
}
impl SimpleMock {
fn mock_fn<'s>(this: &Mut<Self>, s: &'s str, start: usize) -> &'s str {
let context = (s.to_owned(), start);
let str_fn = this.borrow().str_fns.next_for(context);
str_fn(s)
}
}
// Setup mock with 2 functions.
let return_test: StrFn = |_| "test";
let suffix: StrFn = |s| &s[1..];
let mock = SimpleMock {
str_fns: Answers::from_values([return_test, suffix]),
};
let guard = mock.set_as_mock();
// Perform some tests.
assert_eq!(tested_fn("first", 0), "test");
assert_eq!(tested_fn("second", 3), "econd");
// Verify mock calls.
let calls = guard.into_inner().str_fns.take_calls();
assert_eq!(calls.len(), 2);
assert_eq!(calls[0].0, "first");
assert_eq!(calls[1].1, 3);
Implementations
sourceimpl<V, Ctx> Answers<V, Ctx>
impl<V, Ctx> Answers<V, Ctx>
sourcepub fn from_fn<F>(function: F) -> Selfwhere
F: FnMut(&Ctx) -> V + Send + 'static,
pub fn from_fn<F>(function: F) -> Selfwhere
F: FnMut(&Ctx) -> V + Send + 'static,
Answers based on the provided function.
sourcepub fn from_values<I>(iter: I) -> Selfwhere
I: IntoIterator<Item = V>,
I::IntoIter: Send + 'static,
pub fn from_values<I>(iter: I) -> Selfwhere
I: IntoIterator<Item = V>,
I::IntoIter: Send + 'static,
Answers with values from the provided iterator. Once the iterator runs out of items, panics.
sourcepub fn next_for(&mut self, context: Ctx) -> V
pub fn next_for(&mut self, context: Ctx) -> V
Selects an answer based on the specified context
. The context is recorded and can
then be retrieved via Self::take_calls()
.
sourcepub fn take_calls(&mut self) -> Vec<Ctx>
pub fn take_calls(&mut self) -> Vec<Ctx>
Takes contexts for recorded calls since the last call to Self::take_calls()
,
or after creation if called for the first time.
sourceimpl<V: Send + 'static, Ctx> Answers<V, Ctx>
impl<V: Send + 'static, Ctx> Answers<V, Ctx>
sourcepub fn from_value_once(value: V) -> Self
pub fn from_value_once(value: V) -> Self
Answers with the provided value
once. Further calls will panic.
sourcepub fn channel() -> (Self, AnswersSender<V>)
pub fn channel() -> (Self, AnswersSender<V>)
Creates a new Answers
instance that can receive answers dynamically via a channel.
The channel functions similar to a blocking channel
from the standard library.
Unlike with Self::from_value()
/ Self::from_values()
, using a channel allows
building answers dynamically after the mock is already set up.