Hi! I'd like to share a project I've been working on in my free time for the past year.
It's a crate for mocking functions, traits and structs.
https://crates.io/crates/automock
#[automock::mock]
trait Trait {
fn work(&self, v: i32) -> i32;
}
#[test]
fn test() {
// Arrange
let mut mock = TraitMock::new();
mock.setup().work(1).returns_once(2);
// Act
let result = mock.work(1);
// Assert
assert_eq!(result, 2);
mock.verify_calls();
}
It already covers almost all of mockall and faux crates features (two of the most widely used crates for mocking), so I'll focus on some of its advantages in this post:
- Partial mocking - you can configure mocked function to use its original implementation in certain scenarios:
#[automock::mock] trait Trait { fn work(&self, v: i32) -> i32 { 4 // base implementation } } #[test] fn main() { // Arrange let mut mock = TraitMock::new(); mock.setup() .work(1).returns_once(2) .work(3).call_base(); // Act let first = mock.work(1); let second = mock.work(3); // uses base implementation // Assert assert_eq!(first, 2); assert_eq!(second, 4); mock.verify_calls(); } - Static functions mocking - any static function can be mocked, whether it's standalone or associated function:
#[automock::mock] fn work(v: i32) -> i32 { v } #[automock::mock] trait Trait { fn work(v: i32) -> i32; } fn use_trait<T: Trait>(v: i32) -> i32 { T::work(v) } #[test] fn test() { // Arrange work::setup(1).returns_once(2); TraitMock::static_setup().work(3).returns_once(4); // Act let first = work(1); let second = use_trait::<TraitMock>(3); // Assert assert_eq!(first, 2); assert_eq!(second, 4); work::verify_calls(); TraitMock::verify_static_calls(); } - A single
#[mock]attribute for everything - you can apply it to traits, structs, struct implementations, trait on struct implementations or static functions. No need formock!,#[concretize],#[double],#[faux::create]or#[faux::methods]attributes. - Better generics: support for lifetimes and default generic values.
Here's an example of monstrous trait implementation that it can mock
#[mock] impl<'a, 'b: 'a, T1: Clone> Trait<'a, 'b, T1> for Struct<'a, 'b, T1> { fn work<'c, 'd: 'a, T2: Clone>( &self, a: &'a i32, b: &'b i32, c: &'c i32, d: &'d i32, axb: &'a &'_ &'b i32, cxd: &'c &&'d i32, abxbax: &'a &'b &&'b &'a &i32, cdxdcx: &'c &'d &&'d &'c &i32, abcd: &'a &'b &'c &'d i32, xaxbxcxdx: &&'a &&'b &&'c &&'d &i32, data: Data< 'a, 'b, &&i32, &&'a &&'b &[&'c &&'b &Data<'c, 'a, &'_ &&'c &i32, Vec<&'d &'b &()>>], >, t1: T1, t1_ref: &T1, xaxbxcxdx_t1_ref: &&'a &&'b &&'c &&'d &T1, t2: T2, t2_ref: &T2, xaxbxcxdx_t2_ref: &&'a &&'b &&'c &&'d &T2, xapx: &&'a *const &i32, ) -> &&'a &&'a &&'b &&'b &&'c &&'c &&'d &&'d &i32 { Struct::<'a, 'b, T1>::work( self, a, b, c, d, axb, cxd, abxbax, cdxdcx, abcd, xaxbxcxdx, data, t1, t1_ref, xaxbxcxdx_t1_ref, t2, t2_ref, xaxbxcxdx_t2_ref, xapx, ) } }Full example: automock/automock/tests/reference_tests.rs at af3eb2f069dc9efd33e8bbdc94442f0e0d2585e1 · alordash/automock · GitHub
You can see full list of features in the crate's documentation: automock - Rust
Source code: GitHub - alordash/automock: Universal mocks in Rust. · GitHub