Name Description Size Coverage
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 -