galvanic-mock 0.1.3

A behaviour-driven mocking framework for generic traits. Create mocks for (multiple) traits in a behaviour-driven development mocking framework. Define the behaviour of mocks and expected method calls using argument patterns. Supports mocking of generic traits and generic methods. Requires: nightly
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
# Galvanic-mock: behaviour-driven mocking for generic traits
[![Build Status](https://travis-ci.org/mindsbackyard/galvanic-mock.svg?branch=master)](https://travis-ci.org/mindsbackyard/galvanic-mock)
[![Crates.io](https://img.shields.io/crates/v/galvanic-mock.svg)](https://crates.io/crates/galvanic-mock)

This crate provides procedural macros (`#[mockable]`, `#[use_mocks]`) for mocking the behaviour of traits.

 * define given **behaviours** for mock objects based on **patterns**
 * state **expectations** for interactions with mocks
 * mock **multiple** traits at once
 * mock **generic traits** and **traits with associated types**
 * mock **generic trait methods**
 * apply **#[derive(..)]** and other attributes to your mocks
 * **[galvanic-assert]https://www.github.com/mindsbackyard/galvanic-assert** matchers like `eq`, `lt`, ... can be used in behaviours
 * integrate with **[galvanic-test]https://www.github.com/mindsbackyard/galvanic-test** and **[galvanic-assert]https://www.github.com/mindsbackyard/galvanic-assert**
 * be used with your favourite test framework

 The crate is part of **galvanic**---a complete test framework for **Rust**.
 The framework is shipped in three parts, so you can choose to use only the parts you need.

## A short introduction to galvanic-mock

In a well designed software project with loose coupling and dependency injection,
a mock eases the development of software tests. It imitates the behaviour of a *real* object,
i.e., an object present in the production code, to decouple a tested software component from the rest of the system.

**Galvanic-mock** is a behaviour-driven mocking library for traits in Rust.
It allows the user to create a mock object for one or multiple traits emulating their behaviour according to **given** patterns of interaction.
A pattern for a trait's method consists of a boolean matcher for its argument (either for each argument or for all at once), a constant or function calculating the return value, and a the number of repetitions for which the pattern is valid.

```rust
// this crate requires a nightly version of rust
#![feature(proc_macro)]
extern crate galvanic_mock;
use galvanic_mock::{mockable, use_mocks};

#[mockable]
trait MyTrait {
    fn foo(&self, x: i32, y: i32) -> i32;
}

#[test]
#[use_mocks]
fn simple_usage_of_mocks() {
    // create a new object implementing `MyTrait`
    let mock = new_mock!(MyTrait);
    let some_calculation = 1 + 2*3;

    // define behaviours how your mocks should react given some input
    given! {
        // make val available to your behaviours (must implement `Clone`), the type is **not** optional!
        bind val: i32 = some_calculation;

        // define input matchers per argument and return a constant value whenever it matches
        <mock as MyTrait>::foo(|&x| x < 7, |&y| y % 2 == 0) then_return 12 always;
        // or define a single input matcher for all arguments and return the result of a function
        <mock as MyTrait>::foo |&(x, y)| x < y then_return_from |&(x,y)| y - x always;
        // with the `bound` variable you can access variable declared with `bind VAR: TYPE = VALUE;`
        <mock as MyTrait>::foo(|_| true) then_return_from |&(x,_)| x*bound.val always;
    }

    // only matches the last behaviour
    assert_eq!(mock.foo(12, 4), 84);
    // would match the first and the second behaviour, but the first matching behaviour is always used
    assert_eq!(mock.foo(3, 4), 12);
    // matches the second behaviour
    assert_eq!(mock.foo(12, 14), 2);
}
```

Besides emulating the behaviour of an object it is also possible to state expectations about the interactions with object.
Patterns for **expected** behaviours work similar to pattterns for given behaviours.
The example below illustrates these concepts.

```rust
#![feature(proc_macro)]
extern crate galvanic_mock;
use galvanic_mock::{mockable, use_mocks};

// matchers from galvanic_assert can be used as argument matchers
extern crate galvanic_assert;
use galvanic_assert::matchers::{gt, leq, any_value};

#[mockable]
trait MyTrait {
    fn foo(&self, x: i32, y: i32) -> i32;
}

#[mockable]
trait MyOtherTrait<T> {
    fn bar(&self, x: T) -> T;
}

#[test]
#[use_mocks]
fn simple_use_of_mocks() {
    // to mock multiple traits just separate them with a colon
    // specify all types for generic traits as you would specify a type
    let mock = new_mock!(MyTrait, MyOtherTrait<String>);

    // expectations are matched top-down, but once the specified match count is reached it won't match again
    given! {
        // instead of repeating the trait over and over, you can open a block
        <mock as MyTrait>::{
            // this behaviour will match only twice
            foo any_value() then_return_from |_| 7 times 2;
            foo(gt(12), any_value()) then_return 2 always;
        };
        // for generic traits all generic types and associated types need to be given
        <mock as MyOtherTrait<String>>::bar(|x| x == "hugo") then_return "got hugo".to_string() always;
    }

    // expectations are matched top-down, but will never be exhausted
    expect_interactions! {
        // `times` expects an exact number of matching interactions
        <mock as MyOtherTrait<String>>::bar any_value() times 1;
        // besides `times`, also `at_least`, `at_most`, `between`, and `never` are supported
        // all limits are inclusive
        <mock as MyTrait>::foo(any_value(), leq(2)) between 2,5;
    }

    assert_eq!(mock.foo(15, 1), 7);
    assert_eq!(mock.bar("hugo".to_string()), "got hugo".to_string());
    assert_eq!(mock.foo(15, 2), 7);
    assert_eq!(mock.foo(15, 5), 2);

    // the expected interactions are verified when the mock is dropped or when `mock.verify()` is called
}
```


## Documentation

Before reading the documentation make sure to read the examples in the introduction as the documentation will use them as a basis for explanation.

To use the mocking library make sure that you use a **nightly** version of Rust as the crate requires the `proc_macro` feature.
Add the dependency to your `Cargo.toml` preferably as a dev dependency.
```toml
[dev-dependencies]
galvanic-mock = "*" # galvanic uses `semver` versioning
```

At the root of your crate (either `main.rs` or `lib.rs`) add the following to activate the required features and to import the macros.
```rust
#![feature(proc_macro)]
extern crate galvanic_mock;
// The use statement should be placed where the #[mocakable] and #[use_mocks] attributes
// are actually used, or reimported.
use galvanic_mock::{mockable, use_mocks};
```

If we want to use `galvanic-assert` matchers in mocks then we have to enable the `galvanic_assert_integration` feature as follows.
```toml
[dev-dependencies]
galvanic-mock = { version = "*", features = ["galvanic_assert_integration"] }
galvanic-assert = "*" # galvanic-assert uses semver versioning too. To find the version required by `galvanic-mock` check version of the optional dependency in the manifest `Cargo.toml`.
```
If the integration feature is enabled, `extern crate galvanic_assert` has to be specified along with `extern crate galvanic_mock` or the library will fail to compile (even if no `galvanic_assert` matchers are used).

### Defining mockable traits with `#[mockable]`

Before a trait can be mocked, you have to tell the mocking framework about its name, generics, associated types, and methods.
If the trait is part of your own crate you just apply the `#[mockable]` attribute to the trait definition.
```Rust
#[mockable]
trait MyTrait {
    fn foo(&self, x: i32, y: i32) -> i32;
}
```
This registers `MyTrait` as mockable.
Further it assumes that `MyTrait` is defined at the top-level of a crate or that it is always imported by name when mocked, e.g., with `use crate::module::MyTrait`.

If the trait is defined in a submodule, its path should be provided to the attribute.
```Rust
mod sub {
    #[mockable(::sub)]
    trait MyTrait {
        fn foo(&self, x: i32, y: i32) -> i32;
    }
}
```

However the trait is annotated, this will be the only way to refer to it later.
There is no name resolution built in, e.g., the above trait must always be used as `::sub::MyTrait`.
The user of the mocked trait is responsible that the trait is visible to the location where the mock is used under the provided path.
It is therefore recommended that *global* paths are used as in the example above.

#### Mocking *external* traits

An external trait can be mocked by prefixing the path in the attribute with the `extern` keyword.
The full trait definition must be restated, though its definition will be omitted the macro's expansion.
```Rust
#[mockable(extern some_crate::sub)]
trait MyTrait {
    fn foo(&self, x: i32, y: i32) -> i32;
}
```

#### Fixing issues with the macro expansion order

As any other macro, `#[mockable]` is subject to the macro expansion order.
Further a mockable trait must be defined before it can be used.
If this is an issue for an internal trait, its definition can be restated similar to *external* traits.
```Rust
// this occurance of the trait declaration will be removed
#[mockable(intern ::sub)]
trait MyTrait {
    fn foo(&self, x: i32, y: i32) -> i32;
}

// a mock is created somewhere here
...

// the true declaration is encountered later
mod sub {
    trait MyTrait {
        fn foo(&self, x: i32, y: i32) -> i32;
    }
}
```

### Declaring mock usage with `#[use_mocks]`

Any location (`fn`, `mod`) where mocks should be use must be annotated with `#[use_mocks]`.
```Rust
#[test]
#[use_mocks]
fn some_test {
    ...
}
```

If `#[use_mocks]` is applied to a module then the mock types are shared within all submodules and functions.
```Rust
#[use_mocks]
mod test_module {
    #[test]
    fn some_test {
        ...
    }

    #[test]
    fn some_other_test {
        ...
    }
}
```
Though never apply `#[use_mocks]` to an item within some other item which has already a `#[use_mocks]` attribute.

The following macros can only be used within locations annotated with `#[use_mocks]`.

### Creating new mocks with `new_mock!`

To create a new mock object use the `new_mock!` macro followed by a list of mocked traits.
For generic traits specify all their type arguments and associated types.
The created object satisfies the stated trait bounds and may also be converted into a boxed trait object.
```Rust
#[use_mocks]
fn some_test {
    let mock = new_mock!(MyTrait, MyOtherTrait<i32, f64, Assoc=String>);
    ...
}
```
A new mock type will be created for each mock object.
If further attributes should be applied to that type provide them after the type list.
```Rust
#[use_mocks]
fn some_test {
    let mock = new_mock!(MyTrait #[derive(Clone)]#[other_attribute]);
    ...
}
```

When the same mock setup code is shared across multiple tests we can place the mock creation code in a separate factory function, call it in the respective test cases, and modify it further (e.g. adding specific behaviours).
To be able to do this we need to know the name of the created mock type.
So far those types have been anonymous and a name has been chosen by the `new_mock!` command.
It is possible to supply an explicit mock type name.
```Rust
#[use_mocks]
mod test_module {
    fn create_mock() -> mock::MyMockType {
        new_mock!(MyTrait #[some_attribute] for MyMockType)
        ... // define given/expec behaviours
    }

    #[test]
    fn some_test {
        let mock: mock::MyMockType = create_mock();
        ... // define further test=specific given/expec behaviours
    }
}

```
The created type is placed in a `mock` module which is automatically visible to all (sub-)modules and functions within the item annotated with `#[use_mocks]`.

### Defining behaviour with `given!` blocks

After creating a mock object you can invoke the mocked traits' methods on it.
Though as it is just a mock the called methods **will panic** as they don't know what to do.
First you need to define behaviours of the object based on conditions on the method arguments.
Following the terminology of [Behaviour Driven Development (BDD)](https://en.wikipedia.org/wiki/Behavior-driven_development) this is done with a `given!` block.
It sets up the preconditions of the scenario we are testing.
```Rust
given! {
    <mock as MyTrait>::func |&(x, y)| x < y then_return 1 always;
    ...
}
```
A `given!` block consists of several *given statements* with the following pattern.
```Rust
given! {
    <OBJECT as TRAIT>::METHOD ARGUMENT_MATCHERS THEN REPEAT;
    ...
}
```
The statement resembles [Universal Function Call Syntax](https://doc.rust-lang.org/book/first-edition/ufcs.html) with additional components:
* `OBJECT` ... the mock object for which we define the pattern
* `TRAIT` ... the mocked trait to which the `METHOD` belongs. Refering to the trait follows the same rules as `new_mock!`. *The UFC syntax is not optional and for now you must provide generic/associated type arguments in the same order as in the `new_mock!` statement which created the `OBJECT`.*
* `METHOD` ... the method to which the behaviour belongs to
* `ARGUMENT_MATCHERS` ... a precondition on the method arguments which must be fulfilled for the behaviour to be invoked
* `THEN` ... defines what happens after the behaviours has been selected, e.g., return a constant value
* `REPEAT` ... defines how often the behaviour can be matched before it becomes invalid

When a method is invoked its given behaviours' preconditions are checked top-down and the first matching behaviour is selected.
A given block is *not* a global definition and behaves as any other block/statement:
If the control flow never enters the block the behaviours won't be added to the mock object.
If a block is entered multiple times or if another block is reached, then its behaviours are appended to the current list of behaviours.

As writing the full UFC syntax gets tiresome if many behaviours need to be defined for a mock object, a bit of syntactic sugar has been added.
```Rust
given! {
    <OBJECT as TRAIT>::{
        METHOD ARGUMENT_MATCHERS THEN REPEAT;
        METHOD ARGUMENT_MATCHERS THEN REPEAT;
        ...
    };
    ...
}
```
These behaviour blocks get rid of unnecessary duplication.
Note that the semicolon at the end of the block is *not optional*.

*Further note that mocking **static** methods is currently not supported!*.

#### Argument patterns

Preconditions on the method arguments can be defined in two forms: **per-argument** and **explicit**.

##### Per-Argument Patterns

Most of the time per-argument patterns will be enough and are considered more readable.
```Rust
given! {
    <mock as MyTrait>::func(|&x| x == 2, |&y| y < 3.0) then_return 1 always;
}
```
The argument matchers follow the closure syntax and its parameters are passed *by immutable reference* and must return a `bool` or something that implements `std::convert::Into<bool>`.
Although we use closure syntax, **this is not a closure** meaning that you can't capture variables from the scope outside the given block.
We will learn later how we can **bind** values from the outer scope to make them available to the given statements.

If the `galvanic_assert_integration` feature is enabled then the matchers from `galvanic-assert` can be used instead of the closure syntax.
See the introduction for some examples

##### Special Case: Void Patterns

To match a method without arguments we have to use per-argument patterns though without passing a pattern. We refer to the form below as *void pattern*.
```Rust
given! {
    <mock as MyTrait>::func_without_args() then_return 1 always;
}
```

##### Explicit Patterns
The second form receives all arguments at once in a tuple.
```Rust
given! {
    <mock as MyTrait>::func |&(x, y)| x < y then_return 1 always;
}
```
Again the tuple of curried arguments is passed by reference.
Note that we have to use `ref` when decomposing tuples with non-copyable objects (as in any other pattern in Rust).
Observe the **lack of brackets** after `func` in this form.
The brackets are used to distinguish between the two variants.

**Note that *explicit patterns* cannot be used for methods without arguments.**

#### Returning values

Defining the behaviours' actions once selected is done in the `THEN` part of the statement.
We can either return the value of a constant expression with `then_return`:
```RUST
given! {
    <mock as MyTrait>::func ... then_return (1+2).to_string() always;
}
```

Or we compute a value based on the arguments of the function call with `then_return_from`.
The arguments are again passed as a reference to curried argument tuple.
Note again that we use closure syntax but we cannot capture variables from the outside scope.
```RUST
given! {
    <mock as MyTrait>::func ... then_return_from |&(x,y)| (x + y)*2 always;
}
```
Or simply panic:
```RUST
given! {
    <mock as MyTrait>::func ... then_panic always;
}
```

#### Repetition

The final element of a behaviour is the number of *matching* repetitions before the behaviour is exhausted and will no longer match.
The may either be `always` (as used up to now) or `times` followed by an integer expression.
```Rust
let x: i32 = func()

given! {
    <mock as MyTrait>::func |&(x, y)| x < y then_return 1 times x+1;
}
```
Contrary to argument matchers and then-expressions the `times` expression is evaluated in the context of the given block.

#### Binding values from the outer scope

Up until now argument matchers and then-expressions cannot refer to the outside context.
The reason for this is mainly due to lifetime issues with references when actual closures would be passed to the mock objects.
To get around these issues it is possible to **bind** values from the outside scope in a given block.
```Rust
let x = 1;
given! {
    bind value1: f64 = 12.23;
    bind value2: i32 = x*2;

    <mock as MyTrait>::func |&(_, y)| y > bound.value2 then_return bound.value1 always;
    <mock as MyTrait>::func |&(_, y)| y <= bound.value2 then_return_from |&(x, _)| x*bound.value1 always;
}
```
Bind statements must occur before the given statements with the general form:
```Rust
given! {
    bind VARIABLE: TYPE = EXPRESSION:
    ...
}
```
Note that the type is not optional here.
All variables defined with `bind` can later be accessed with a member of the `bound` variable.
The bind expressions will be evaluated when the given block is entered.
That also means if a given block is entered multiple times the bind statements will be reevaluated for the new behaviours.

#### Behaviours for generic trait methods

Be careful when you try to mock *generic methods* as below.
```Rust
#[mockable]
trait MyTrait {
    fn generic_func<T,F>(x: T, y: F) -> T;
}
...
given! {
    <mock as MyTrait>::generic_func |&(ref x, ref y)| ... then_return 1 always;
}
```
The behaviour will be applied regardless of the actual types used.
Meaning that besides the trait bounds defined on the type arguments you cannot use much else.
We cannot assume, e.g., that `x` is always a `i32` although we might know that depending on the context.
In such a case we must either detect the type ourselves or use `unsafe` casts.
*This will likely change in future versions and get easier/more useful.*

#### Behaviours for static trait methods

*This is currently not supported but is high priority for one of the next versions.*


### Expecting interactions with `expect_interactions!` blocks

Besides defining how a mock should act it is a common use case to want to know that some interactions, i.e., method calls, happened with the mock.
This can be done with an expect block which works similar to given blocks.
```Rust
expect_interactions! {
    <mock as MyTrait>::func(|&x| x == 2, |&y| y < 12.23) times 2;
}
```
Again the block consists of several expect statements with the following general form.
```Rust
expect_interactions! {
    <OBJECT as TRAIT>::METHOD ARGUMENT_MATCHERS REPEAT;
    ...
}
```
Trait blocks, argument matchers, bindings, and evaluation order work in the same way as given blocks.
Repeat expressions support a few different options.
Further a expect behaviour will never be exhausted.
The expect statements only specify the testing order of the patterns, they do not specify the expected order of interactions.
The order of interactions in a `expect_interactions` block is assumed to be arbitrary.
Also only the first matching expect expression will be counted.
Later expression whose argument matchers would also be satisfied with the same arguments will not be evaluated.

*Specifying a fixed order is currently not supported.*

The expectations are verified once the mock object is dropped or if `mock.verify()` is called.
If the expected interactions did not happen as specified when verified the current thread will panic.
If other interactions not matching any expect behaviour occured then they won't be seen as errors.

#### Repetition

The repeat expressions for a expect block can be one of the following.
* `times EXPRESSION` ... states that *exactly* `EXPRESSION` number of matches must occur.
* `never` ... states the interaction should never be encountered (same as `times 0`).
* `at_least EXPRESSION` ... states that at least `EXPRESSION` (inclusive) number of matches must occur.
* `at_most EXPRESSION` ... states that at most `EXPRESSION` (inclusive) number of matches must occur.
* `between EXPRESSION1, EXPRESSION2` ... states that a number of matches in the inclusive range [`EXPRESSION1`, `EXPRESSION2`] should occur.

### The `Mock` interface

All mocks support some basic methods for controlling the mock.
* `should_verify_on_drop(bool)` ... if called with `false` verification on drop will be disabled and vice versa.
* `reset_given_behaviours()` ... removes all given behaviours from the mock
* `reset_expected_behaviours()` ... removes all expectations from the mock
* `are_expected_behaviours_satisfied()` ... return `true` if all expectations are currently satisfied, `false` otherwise.
* `verify()` ... panics if some expectaions are currently unsatisfied.