Skip to content

Commit

Permalink
Add slide to show the Mockall crate in action
Browse files Browse the repository at this point in the history
  • Loading branch information
mgeisler committed Nov 30, 2023
1 parent bb58ec9 commit 2ae0cbf
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 0 deletions.
112 changes: 112 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@
- [Test Modules](testing/unit-tests.md)
- [Other Types of Tests](testing/other.md)
- [Useful Crates](testing/useful-crates.md)
- [Mocking](testing/mocking.md)
- [Compiler lints and Clippy](testing/lints.md)
- [Exercise: Luhn Algorithm](testing/exercise.md)
- [Solution](testing/solution.md)
Expand Down
7 changes: 7 additions & 0 deletions src/testing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ version = "0.1.0"
edition = "2021"
publish = false

[[example]]
name = "mockall-example"
crate-type = ["staticlib"]
path = "mockall.rs"
test = true

[[bin]]
name = "luhn"
path = "exercise.rs"

mockall = "0.11.4"
13 changes: 13 additions & 0 deletions src/testing/mockall.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use std::time::Duration;

#[mockall::automock]
pub trait Pet {
fn is_hungry(&self, since_last_meal: Duration) -> bool;
}

#[test]
fn test_robot_pet() {
let mut mock_dog = MockPet::new();
mock_dog.expect_is_hungry().return_const(true);
assert_eq!(mock_dog.is_hungry(Duration::from_secs(10)), true);
}
58 changes: 58 additions & 0 deletions src/testing/mocking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
minutes: 10
---

# Mocking

If you want to do mocking, we recommend [Mockall]. You need to refactor your
code to use traits, which you can then quickly mock:

```rust,ignore
{{#include mockall.rs}}
```

[Mockall]: https://docs.rs/mockall/

<details>

- Note that *mocking is controversial*: mocks allow you to completely isolate a
test from its dependencies. The immediate result is faster and more stable
test execution. On the other hand, the mocks can be configured wrongly and
return output different from what the real dependencies would do.

If at all possible, it is recommended that you use the real dependencies. As
an example, many databases allow you to configure an in-memory backend. This
means that you get the correct behavior in your tests, plus they are fast and
will automatically clean up after themselves.

Similarly, many web frameworks allow you to start an in-process server which
binds to a random port on `localhost`. Always prefer this over mocking away
the framework since it helps you test your code in the real environment.

- Mockall is not part of the Rust Playground, so you need to run this example in
a local environment. Use `cargo add mockall` to quickly add Mockall to an
existing Cargo project.

- Mockall has a lot more functionality. In particular, you can set up
expectations which depend on the arguments passed:

```rust,ignore
let mut mock_cat = MockPet::new();
mock_cat
.expect_is_hungry()
.with(mockall::predicate::gt(Duration::from_secs(3 * 3600)))
.return_const(true);
mock_cat
.expect_is_hungry()
.return_const(true);
assert_eq!(mock_cat.is_hungry(Duration::from_secs(1 * 3600)), false);
assert_eq!(mock_cat.is_hungry(Duration::from_secs(5 * 3600)), true);
```
- You can use `.times(n)` to limit the number of times a mock method can be
called to `n` --- the mock will automatically panic when dropped if this isn't
satisfied.
- Mockall is available for use in AOSP.
</details>

0 comments on commit 2ae0cbf

Please sign in to comment.