6 releases (stable)

1.1.0 Jan 1, 2021
1.0.2 Dec 7, 2020
1.0.1 Aug 31, 2020
0.1.0 Aug 21, 2020
0.0.1 Aug 20, 2020

#56 in Testing

Download history 4745/week @ 2020-11-07 5561/week @ 2020-11-14 4961/week @ 2020-11-21 5402/week @ 2020-11-28 6233/week @ 2020-12-05 5595/week @ 2020-12-12 3518/week @ 2020-12-19 3425/week @ 2020-12-26 5833/week @ 2021-01-02 6147/week @ 2021-01-09 5353/week @ 2021-01-16 5551/week @ 2021-01-23 6231/week @ 2021-01-30 5252/week @ 2021-02-06 6174/week @ 2021-02-13 6486/week @ 2021-02-20

19,229 downloads per month
Used in less than 16 crates

MIT/Apache

18KB
383 lines

expect-test

Minimalistic snapshot testing for Rust.

Updating a failing test:

expect

Adding a new test:

expect-fresh


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:

use expect_test::expect;

let actual = 2 + 2;
let expected = 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:

# 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, expect! macro uses file! and line! 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:

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 - a more feature full snapshot testing library.
  • 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 expected to be relatively stable, but, if the need arises, it could be significantly reworked to fit rust-analyzer better.

MSRV: latest stable.

Dependencies

~125KB