View Source snap_assert
An experiment in self-modifying code, or, instant snapshot testing inside your unit tests.
The snap_assert macro inserts the result of evaluating its argument directly into your source code as its second argument.
snap_assert with two arguments becomes a regular ex_unit assert.
Installation
If available in Hex, the package can be installed
by adding snap_assert to your list of dependencies in mix.exs:
def deps do
[
{:snap_assert, "~> 0.1.0"}
]
endDocumentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/snap_assert.
Usage
- Import
Snapin your test file - Use
snap_assert <some expression>in one of the tests - Run the tests with
mix test - Tests will pass and
snap_assert <some expression>will turn intosnap_assert <some expression>, <expression value> - Run the tests again;
snap_assertwith two arguments will now be equivalent to a regular assert so tests will pass.
More concrete example:
- Add
snap_assert(String.upcase("hello"))to a test - Run
mix test(tests will pass) - The test file is now updated so that you have
snap_assert(String.upcase("hello"), "HELLO") - Run
mix testagain - tests will pass - Change the expression to
snap_assert(String.upcase("hello"), "GOODBYE") - Run
mix testagain - tests will fail, ie. now you have a regular assert.
When working with snap_assert, it's useful to have the tests run on every change, for example with:
fswatch lib test | mix test --listen-on-stdin --staleWhy?
I was inspired by this post by Ian Henry: https://ianthehenry.com/posts/my-kind-of-repl/
At first, the idea of inserting the value of an expression into an assert seems tautological. However, consider how we often write functions: start with a draft implementation, try it out in the REPL, realise it's incomplete, make tweaks, try again, repeat until done. Then write unit tests, possibly by copy-pasting from the REPL.
snap_assert moves some of that REPL into your test file. When you run tests which include a snap_assert,
you'll see the results directly in your test file. If they are as expected - great, you now have a unit test
for free. If not, delete the incorrect value, fix your function, run the tests again. Rinse and repeat.
I was skeptical at first, but I've been trying this macro while working on a package, and it feels good.
Of course, snap_assert isn't suitable for all tests: sometimes you want to check for a substring match, or a pattern match,
or check that a message is received, and in those cases you still need to use regular ex_unit functionality.