[−][src]Attribute Macro faux::methods
#[methods]
Transforms the given methods into mockable versions of themselves and provides a new method to mock them.
The generated methods look like
impl MyStruct { /* other methods before */ // I is a tuple of all the non-receiver arguments of #{method_name} // O is the output of #{method_name} _when_#{method_name}(&mut self) -> When<I,O> { /* auto generated code */ } }
These auto-generated methods can be called directly but a more ergonomic way is by using when!.
Associated functions and private methods are not mocked, and are instead proxied to the real implementation.
Requirements
#[create] must have been previously called for this struct.
Known Limitations
#10: impl SomeTrait for SomeStruct {}
is not supported.
#11: impl path::to::SomeStruct {}
is not supported.
#13: Only a simple impl block may exist per module per type.
#14: Methods may not contain instances of the same struct as parameters.
Usage
#[faux::create] pub struct MyStruct { /* fields */ } #[faux::methods] impl MyStruct { pub fn new(data: Vec<u32>) -> Self { /* implementation code */ } pub fn get(&self) -> usize { 20 } } // #[methods] let real = MyStruct::new(vec![5]); assert_eq!(real.get(), 20); // mock instances need to be mutable when mocking their methods let mut fake = MyStruct::faux(); faux::when!(fake.get).safe_then(|_| 3); assert_eq!(fake.get(), 3);
Panics
Non-mocked methods
Faux will not try to return a default value on non-mocked methods so it panics instead.
#[faux::create] pub struct MyStruct {} #[faux::methods] impl MyStruct { pub fn get(&self) -> usize { 50 } } let fake = MyStruct::faux(); // when!(fake.get).then_safe() was not invoked and thus the method was not mocked fake.get(); // <~ panics with "'MyStruct::get' is not mocked"
Mocking real instances
Spies are not supported and thus mocking real instances panic.
#[faux::create] pub struct MyStruct {} #[faux::methods] impl MyStruct { pub fn new() -> MyStruct { MyStruct {} } pub fn get(&self) -> usize { 50 } } let mut fake = MyStruct::new(); faux::when!(fake.get); // <~ panics with "not allowed to mock a real instance!"
Caveats
Methods/functions that return the mocked struct
Special care is taken for methods and function that return an
instance of the mocked struct. Unfortunately only methods that
return -> Self
or -> #{SomeStruct}
are
handled.
Methods/functions that returns your type wrapped as a generic of
another type (e.g., Result<Self, _>
) cannot be mocked.
#[faux::create] pub struct MyStruct {} #[faux::methods] impl MyStruct { pub fn try_to_new() -> Result<Self, String> { Ok(MyStruct {}) } }
A workaround is to place these functions outside the impl tagged
with #[faux::method]
and have it redirect to the method inside the
tagged impl
#[faux::create] pub struct MyStruct {} #[faux::methods] impl MyStruct { fn new() -> Self { MyStruct {} } } // do not tag this one impl MyStruct { pub fn try_to_new() -> Result<Self, String> { Ok(MyStruct::new()) } } let x = MyStruct::try_to_new(); assert!(x.is_ok());
Mocking struct defined elsewhere in the crate
Faux supports mocking structs from a different module as long as
we tell #[methods]
where we are importing the struct from using
the #[methods(path::to::module)]
mod foo { #[faux::create] pub struct MyStruct {} // no need to tell #[faux::methods] where to find `MyStruct` // if defined in the same module #[faux::methods] impl MyStruct { pub fn three(&self) -> i32 { 3 } } mod foo_inner { use super::MyStruct; // we have to tell #[faux::methods] where we imported MyStruct from #[faux::methods(super)] impl MyStruct { pub fn four(&self) -> i32 { self.three() + 1 } } } } mod bar { use crate::foo::MyStruct; // we have to tell #[faux::methods] where we imported MyStruct from #[faux::methods(crate::foo)] impl MyStruct { pub fn five(&self) -> i32 { self.three() + 2 } } } let mut x = foo::MyStruct::faux(); faux::when!(x.three).safe_then(|_| 30); faux::when!(x.four).safe_then(|_| 40); faux::when!(x.five).safe_then(|_| 50); assert_eq!(x.three(), 30); assert_eq!(x.four(), 40); assert_eq!(x.five(), 50);