| lib.rs |
Minimalistic snapshot testing for Rust.
# Introduction
`expect_test` is a small addition over plain `assert_eq!` testing approach,
which allows to automatically update tests results.
The core of the library is the `expect!` macro. It can be though of as a
super-charged string literal, which can update itself.
Let's see an example:
```no_run
use expect_test::expect;
let actual = 2 + 2;
let expected = expect!["5"]; // or expect![["5"]]
expected.assert_eq(&actual.to_string())
```
Running this code will produce a test failure, as `"5"` is indeed not equal
to `"4"`. Running the test with `UPDATE_EXPECT=1` env variable however would
"magically" update the code to:
```no_run
# use expect_test::expect;
let actual = 2 + 2;
let expected = expect!["4"];
expected.assert_eq(&actual.to_string())
```
This becomes very useful when you have a lot of tests with verbose and
potentially changing expected output.
Under the hood, the `expect!` macro uses `file!`, `line!` and `column!` to
record source position at compile time. At runtime, this position is used
to patch the file in-place, if `UPDATE_EXPECT` is set.
# Guide
`expect!` returns an instance of `Expect` struct, which holds position
information and a string literal. Use `Expect::assert_eq` for string
comparison. Use `Expect::assert_debug_eq` for verbose debug comparison. Note
that leading indentation is automatically removed.
```
use expect_test::expect;
#[derive(Debug)]
struct Foo {
value: i32,
}
let actual = Foo { value: 92 };
let expected = expect![["
Foo {
value: 92,
}
"]];
expected.assert_debug_eq(&actual);
```
Be careful with `assert_debug_eq` - in general, stability of the debug
representation is not guaranteed. However, even if it changes, you can
quickly update all the tests by running the test suite with `UPDATE_EXPECT`
environmental variable set.
If the expected data is too verbose to include inline, you can store it in
an external file using the `expect_file!` macro:
```no_run
use expect_test::expect_file;
let actual = 42;
let expected = expect_file!["./the-answer.txt"];
expected.assert_eq(&actual.to_string());
```
File path is relative to the current file.
# Suggested Workflows
I like to use data-driven tests with `expect_test`. I usually define a
single driver function `check` and then call it from individual tests:
```
use expect_test::{expect, Expect};
fn check(actual: i32, expect: Expect) {
let actual = actual.to_string();
expect.assert_eq(&actual);
}
#[test]
fn test_addition() {
check(90 + 2, expect![["92"]]);
}
#[test]
fn test_multiplication() {
check(46 * 2, expect![["92"]]);
}
```
Each test's body is a single call to `check`. All the variation in tests
comes from the input data.
When writing a new test, I usually copy-paste an old one, leave the `expect`
blank and use `UPDATE_EXPECT` to fill the value for me:
```
# use expect_test::{expect, Expect};
# fn check(_: i32, _: Expect) {}
#[test]
fn test_division() {
check(92 / 2, expect![[""]])
}
```
See
<https://blog.janestreet.com/using-ascii-waveforms-to-test-hardware-designs/>
for a cool example of snapshot testing in the wild!
# Alternatives
* [insta](https://crates.io/crates/insta) - a more feature full snapshot
testing library.
* [k9](https://crates.io/crates/k9) - a testing library which includes
support for snapshot testing among other things.
# Maintenance status
The main customer of this library is rust-analyzer. The library is stable,
it is planned to not release any major versions past 1.0.
## Minimal Supported Rust Version
This crate's minimum supported `rustc` version is `1.60.0`. MSRV is updated
conservatively, supporting roughly 10 minor versions of `rustc`. MSRV bump
is not considered semver breaking, but will require at least minor version
bump. |
25259 |
- |