mocktopus/
lib.rs

1#![feature(fn_traits, tuple_trait, unboxed_closures)]
2
3//! Mocking framework for Rust (currently only nightly)
4//!
5//! ```
6//! #[mockable]
7//! mod hello_world {
8//!     pub fn world() -> &'static str {
9//!         "world"
10//!     }
11//!
12//!     pub fn hello_world() -> String {
13//!         format!("Hello {}!", world())
14//!     }
15//! }
16//!
17//! #[test]
18//! fn mock_test() {
19//!     hello_world::world.mock_safe(|| MockResult::Return("mocking"));
20//!
21//!     assert_eq!("Hello mocking!", hello_world::hello_world());
22//! }
23//! ```
24//! # Introduction
25//! This is a user guide showing Rust project set up for testing with mocks.
26//!
27//! It is highly recommended to **use mocks ONLY for test runs and NEVER in release builds!**
28//! Mocktopus is not designed for high performance and will slow down code execution.
29//!
30//! Note: this guide shows set up of mocking for test builds only.
31//! # Prerequisites
32//! Add Mocktopus dev-dependency to project's `Cargo.toml`:
33//!
34//! ```
35//! [dev-dependencies]
36//! mocktopus = "0.7.0"
37//! ```
38//! Enable procedural macros in crate root:
39//!
40//! ```
41//! #![cfg_attr(test, feature(proc_macro_hygiene))]
42//! ```
43//! Import Mocktopus (skip for Rust 2018):
44//!
45//! ```
46//! #[cfg(test)]
47//! extern crate mocktopus;
48//! ```
49//! # Making functions mockable
50//! To make functions mockable they must be annotated with provided procedural macros.
51//! See [documentation](https://docs.rs/mocktopus_macros) for all their possibilities and rules.
52//!
53//! To use these macros import them into namespace:
54//!
55//! ```
56//! #[cfg(test)]
57//! use mocktopus::macros::*;
58//! ```
59//! Annotate mockable code like standalone functions or impl blocks:
60//!
61//! ```
62//! #[mockable]
63//! fn my_fn() {}
64//!
65//! #[mockable]
66//! impl Struct {
67//!     fn my_method() {}
68//! }
69//! ```
70//! It's NOT legal to annotate single funciton in impl block:
71//!
72//! ```
73//! impl Struct {
74//!     #[mockable] // WRONG, will break Mocktopus
75//!     fn my_method() {}
76//! }
77//! ```
78//! It is possible to annotate modules, which makes all their potentially mockable content mockable:
79//!
80//! ```
81//! #[cfg_attr(test, mockable)]
82//! mod my_module {
83//!     fn my_fn() {}
84//! }
85//! ```
86//! This does NOT work for modules in separate file:
87//!
88//! ```
89//! #[cfg_attr(test, mockable)] // WRONG, has no effect
90//! mod my_module;
91//! ```
92//! # Mocking
93//! Import tools for mocking in test module:
94//!
95//! ```
96//! #[cfg(test)]
97//! mod tests {
98//!     use mocktopus::mocking::*;
99//! ```
100//! Among others this imports trait `Mockable`.
101//! It is implemented for all functions and provides an interface for setting up mocks:
102//!
103//! ```
104//! #[test]
105//! fn my_test() {
106//!     my_function.mock_safe(|| MockResult::Return(1));
107//!
108//!     assert_eq!(1, my_function());
109//! }
110//! ```
111//! It is also possible to mock struct methods, either from own impls, traits or trait defaults:
112//!
113//! ```
114//! // Mocking method
115//! MyStruct::my_method.mock_safe(|| MockResult::Return(1));
116//! // Mocking trait method
117//! MyStruct::my_trait_method.mock_safe(|| MockResult::Return(2));
118//! // Mocking default trait method
119//! MyStruct::my_trait_default_method.mock_safe(|| MockResult::Return(3));
120//! ```
121//! Mocking with `mock_safe` is simplest, but the `Mockable` trait has more,
122//! see [documantation](mocking/trait.Mockable.html).
123//!
124//! ## Mocking range
125//! Every mock works only in thread, in which it was set.
126//! All Rust test runs are executed in independent threads, so mocks do not leak between them:
127//!
128//! ```
129//! #[cfg_attr(test, mockable)]
130//! fn common_fn() -> u32 {
131//!     0
132//! }
133//!
134//! #[test]
135//! fn common_fn_test_1() {
136//!     assert_eq!(0, common_fn());
137//!
138//!     common_fn.mock_safe(|| MockResult::Return(1));
139//!
140//!     assert_eq!(1, common_fn());
141//! }
142//!
143//! #[test]
144//! fn common_fn_test_2() {
145//!     assert_eq!(0, common_fn());
146//!
147//!     common_fn.mock_safe(|| MockResult::Return(2));
148//!
149//!     assert_eq!(2, common_fn());
150//! }
151//! ```
152//!
153//! ## Mock closure
154//! `mock_safe` has single argument: a closure, which takes same input as mocked function and returns a `MockResult`.
155//! Whenever the mocked function is called, its inputs are passed to the closure:
156//!
157//! ```
158//! #[cfg_attr(test, mockable)]
159//! fn my_function_1(_: u32) {
160//!     return
161//! }
162//!
163//! #[test]
164//! fn my_function_1_test() {
165//!     my_function_1.mock_safe(|x| {
166//!         assert_eq!(2, x);
167//!         MockResult::Return(())
168//!     });
169//!
170//!     my_function_1(2); // Passes
171//!     my_function_1(3); // Panics
172//! }
173//! ```
174//! If the closure returns `MockResult::Return`, the mocked function does not run.
175//! It immediately returns with a value, which is passed inside `MockResult::Return`:
176//!
177//! ```
178//! #[cfg_attr(test, mockable)]
179//! fn my_function_2() -> u32 {
180//!     unreachable!()
181//! }
182//!
183//! #[test]
184//! fn my_function_2_test() {
185//!     my_function_2.mock_safe(|| MockResult::Return(3));
186//!
187//!     assert_eq!(3, my_function_2());
188//! }
189//! ```
190//! If the closure returns `MockResult::Continue`, the mocked function runs normally, but with changed arguments.
191//! The new arguments are returned from closure in tuple inside `MockResult::Continue`:
192//!
193//! ```
194//! #[cfg_attr(test, mockable)]
195//! fn my_function_3(x: u32, y: u32) -> u32 {
196//!     x + y
197//! }
198//!
199//! #[test]
200//! fn my_function_3_test() {
201//!     my_function_3.mock_safe(|x, y| MockResult::Continue((x, y + 1)));
202//!
203//!     assert_eq!(3, my_function_3(1, 1));
204//! }
205//! ```
206//!
207//! ## Mocking generics
208//! When mocking generic functions, all its generics must be defined and only this variant will be affected:
209//!
210//! ```
211//! #[cfg_attr(test, mockable)]
212//! fn generic_fn<T: Display>(t: T) -> String {
213//!     t.to_string()
214//! }
215//!
216//! #[test]
217//! fn generic_fn_test() {
218//!     generic_fn::<u32>.mock_safe(|_| MockResult::Return("mocked".to_string()));
219//!
220//!     assert_eq!("1", generic_fn(1i32));
221//!     assert_eq!("mocked", generic_fn(1u32));
222//! }
223//! ```
224//! The only exception are lifetimes, they are ignored:
225//!
226//! ```
227//! #[cfg_attr(test, mockable)]
228//! fn lifetime_generic_fn<'a>(string: &'a String) -> &'a str {
229//!     string.as_ref()
230//! }
231//!
232//! #[test]
233//! fn lifetime_generic_fn_test() {
234//!     lifetime_generic_fn.mock_safe(|_| MockResult::Return("mocked"));
235//!
236//!     assert_eq!("mocked", lifetime_generic_fn(&"not mocked".to_string()));
237//! }
238//! ```
239//! Same rules apply to methods and structures:
240//!
241//! ```
242//! struct GenericStruct<'a, T: Display + 'a>(&'a T);
243//!
244//! #[cfg_attr(test, mockable)]
245//! impl<'a, T: Display + 'a> GenericStruct<'a, T> {
246//!     fn to_string(&self) -> String {
247//!         self.0.to_string()
248//!     }
249//! }
250//!
251//! static VALUE: u32 = 1;
252//!
253//! #[test]
254//! fn lifetime_generic_fn_test() {
255//!     GenericStruct::<u32>::to_string.mock_safe(|_| MockResult::Return("mocked".to_string()));
256//!
257//!     assert_eq!("mocked", GenericStruct(&VALUE).to_string());
258//!     assert_eq!("mocked", GenericStruct(&2u32).to_string());
259//!     assert_eq!("2", GenericStruct(&2i32).to_string());
260//! }
261//! ```
262//!
263//! ## Mocking async
264//! Mocking async functions is almost exactly the same as non-async:
265//!
266//! ```
267//! #[cfg_attr(test, mockable)]
268//! async fn sleep(ms: u64) {
269//!     tokio::time::delay_for(std::time::Duration::from_millis(ms)).await;
270//! }
271//!
272//! #[tokio::test]
273//! async fn sleep_test() {
274//!     sleep.mock_safe(|_| MockResult::Return(Box::pin(async move { () })));
275//!
276//!     sleep(10000).await;
277//! }
278//! ```
279//!
280//! # Mocking tricks
281//! ## Returning reference to value created inside mock
282//!
283//! ```
284//! #[mockable]
285//! fn my_fn(my_string: &String) -> &String {
286//!     my_string
287//! }
288//!
289//! #[test]
290//! fn my_fn_test() {
291//!     my_fn.mock_safe(|_| MockResult::Return(Box::leak(Box::new("mocked".to_string()))));
292//!
293//!     assert_eq!("mocked", my_fn(&"not mocked 1"));
294//!     assert_eq!("mocked", my_fn(&"not mocked 2"));
295//! }
296//! ```
297//! The trick is to store referenced value in a `Box::new` and then prevent its deallocation with `Box::leak`.
298//! This makes structure live forever and returns a `&'static mut` reference to it. The value is not freed until
299//! process termination, so it's viable solution only for use in tests and only if structure doesn't block a lot of
300//! resources like huge amounts of memory, open file handlers, sockets, etc.
301//!
302//! ## Returning value created outside of mock
303//!
304//! ```
305//! #[mockable]
306//! fn my_fn() -> String {
307//!     "not mocked".to_string()
308//! }
309//!
310//! #[test]
311//! fn my_fn_test() {
312//!     mock = Some("mocked".to_string());
313//!     my_fn.mock_safe(move || MockResult::Return(mock.unwrap()));
314//!
315//!     assert_eq!("mocked", my_fn());
316//!     // assert_eq!("mocked", my_fn()); // WILL PANIC!
317//! }
318//! ```
319//! This makes function return predefined value on first call and panic on second one. It could return
320//! `MockResult::Continue` instead of panicking to mock only first call.
321//!
322//! Returned values can be stored in a vector if mock should return different value on different calls:
323//!
324//! ```//!
325//! #[test]
326//! fn my_fn_test() {
327//!     mut mock = vec!["mocked 1".to_string(), "mocked 2".to_string()];
328//!     my_fn.mock_safe(move || MockResult::Return(mock.remove(0)));
329//!
330//!     assert_eq!("mocked 1", my_fn());
331//!     assert_eq!("mocked 2", my_fn());
332//!     // assert_eq!("mocked 3", my_fn()); // WILL PANIC!
333//! }
334//! ```
335//! The vector can store `MockResult`s for more complex mocking.
336#![doc(
337    html_logo_url = "https://raw.githubusercontent.com/CodeSandwich/mocktopus/master/logo.png",
338    html_favicon_url = "https://raw.githubusercontent.com/CodeSandwich/mocktopus/master/logo.png"
339)]
340
341extern crate mocktopus_macros;
342
343/// For use in testing code: mocking tools
344pub mod mocking;
345
346/// For use in testing code: helper tools for writing tests using mocking
347pub mod mocking_utils;
348
349/// For use in tested code: tools making items mockable
350pub mod macros {
351    pub use mocktopus_macros::*;
352}
353
354mod mock_store;