Fun Fixture Tests in Rust
Recently, I've been working on an interpreter/shell (wsh). For projects like this, I want to make sure I have lots of tests! However, as my features got more complex and nuanced, I found it hard to freely write tests in a streamlined manner.
For example, let's say you're testing a simple interpreter. Writing tests for it should normally involve you doing something like this:
#[test]
fn some_math() {
let input = "1 + 1";
let expected = 2;
// ...
}
No problem, right? But what happens when you need to test semi-complex control flow?
#[test]
fn looping_and_break() {
let input = "x = 0\nwhile true:\n x += 1\n if x == 10:\n break\nx";
let expected = 10;
// ...
}
Not as nice... and while you can use multiline strings (or even use the
indoc
macro), there is still some
boilerplate, and it began to bother me. Yes, a solution might be unnecessary.
But it's fun (and it looks cool)!
Okay, so what if we had a test that:
- Is described by a file
- Has arbitrary metadata at the top
- Gets its own entry in the
cargo test
output
Maybe something like this:
---
expected: 10
---
x = 0
while true:
x += 1
if x == 10:
break
x
This is called a test fixture, and is a common pattern for certain types of software.
Inspiration & Implementation
The idea for this style of test was inspired by the excellent WABT project. Their tests are run by a much more complicated fixture harness than what my implementation has (with their own fancy DSL), so if you want to look at something more robust, definitely check WABT out.
My own implementation
is largely driven by serde and
dir-test. Serde is used to parse the
metadata (in the ---
), and dir-test is used to generate tests cases based on
files in a directory (at compile time). So, every file in the
fixtures directory
corresponds to a test.
If you want to use this style of testing in your own project, keep in mind that my implementation is for a shell, so some parts may have to be adapted. It's quite simple though (only about ~80 lines); it shouldn't be too hard to apply to something else!
Closing Thoughts
Using this style of testing in wsh has been pretty great! It was fun to implement, and it's now much nicer to write tests. It also helps when viewing diffs, which was an unexpected bonus when I first wrote the fixture harness.
Let me know if you have any further questions or if there were any issues you found in this post!