when!() { /* proc-macro */ }
Expand description
Creates a When
instance to stub a specific method in a struct.
Callers may specify argument matchers to limit the arguments for
which the method is stubbed. Matchers can only be specified if all
arguments implement Debug
. The debug message
is printed if any of the arguments fail to match.
The method to stub must be be in an impl
blocked tagged by
#[methods]
.
§Examples
#[faux::create]
pub struct Foo {}
#[faux::methods]
impl Foo {
pub fn some_method(&self, a: u32, b: i8) -> i32 {
/* implementation code */
}
}
fn main() {
let mut mock = Foo::faux();
// specify all arguments
faux::when!(mock.some_method(8, 9)).then_return(10);
// actual method calls have to match expectations
assert_eq!(mock.some_method(8, 9), 10);
// mock.some_method(1, 1); // <~~ panics - arguments do not match
// check only the second argument
faux::when!(mock.some_method(_, 4)).then_return(20);
// only the second argument is being matched against
// so the first argument could be anything
assert_eq!(mock.some_method(999, 4), 20);
assert_eq!(mock.some_method(123, 4), 20);
// mock.some_method(999, 3); // <~~ panics - second argument does not match
// no argument matchers
faux::when!(mock.some_method).then_return(3);
// the arguments do not matter at all
assert_eq!(mock.some_method(1337, 20), 3);
assert_eq!(mock.some_method(4, 5), 3);
assert_eq!(mock.some_method(7, 6), 3);
}
An argument mismatch would look something like:
thread 'main' panicked at 'failed to call stub on 'Foo::some_method':
✗ Arguments did not match
Expected: [8, 9]
Actual: [1, 1]
Argument 0:
Expected: 8
Actual: 1
Argument 1:
Expected: 9
Actual: 1
§Argument Matchers
Argument matchers are specified by passing them to when!
:
faux::when!(my_struct.my_method(/* matchers here */));
This rougly translates to:
faux::when!(my_struct.my_method).with_args((/* matchers here */));
§Matcher syntax
To make argument matching easy to use, when!
provides some
syntactic sugar that converts given arguments to the appropiate
ArgMatcher
and passes them to with_args
. If this proves
difficult in your use case, you can use with_args
directly.
Each of the following specify an equivalent ArgMatcher
for a
single argument:
when! arg | ArgMatcher |
---|---|
{expr} | eq({expr}) |
_ | any() |
_ == {expr} | eq_against({expr}) |
_ = {matcher} | {matcher} |
Replace _
with *_
in the last two rows to match against
references. More specifically, this converts the matcher from
ArgMatcher<T>
into ArgMatcher<&T>
using into_ref_matcher
.
§Examples
#[faux::create]
pub struct MyStruct;
#[faux::methods]
impl MyStruct {
pub fn my_method(&self, a: &i32, b: i32) -> i32 {
panic!()
}
}
let mut my_struct = MyStruct::faux();
// the eq matcher works even though the first argument is a reference
// the `_` matcher will match any argument
faux::when!(my_struct.my_method(3, _)).then_return(4);
assert_eq!(my_struct.my_method(&3, 20), 4);
// a type that implements `PartialEq<i32>` but is not an `i32`
#[derive(Debug)]
struct OtherNumber(i64);
impl PartialEq<i32> for OtherNumber {
fn eq(&self, rhs: &i32) -> bool {
self.0 == *rhs as i64
}
}
// `_ == {expr}` to test equality of different types
// `*_ == {expr}` to dereference an argument before matching
faux::when!(my_struct.my_method(
*_ == OtherNumber(5),
_ == OtherNumber(20),
)).then_return(8);
assert_eq!(my_struct.my_method(&5, 20), 8);
// `_ = {matcher}` will pass the matcher to `with_args` as written
// `*_ = {matcher}` will match against a dereferenced argument
faux::when!(my_struct.my_method(
*_ = faux::matcher::eq_against(OtherNumber(4)),
_ = faux::matcher::eq(9),
)).then_return(20);
assert_eq!(my_struct.my_method(&4, 9), 20);
// pattern! and from_fn! are allowed just as any other matcher
faux::when!(my_struct.my_method(
*_ = faux::pattern!(10..=20),
_ = faux::from_fn!(|arg: &i32| *arg > 50),
)).then_return(80);
assert_eq!(my_struct.my_method(&11, 60), 80);