DeltaCheck - A testing toolkit for making assertions on database writes

Hi everyone!

I’ve been working on DeltaCheck lately, a small testing library that provides a concise API for tracking and asserting on what changes your code makes and doesn’t make in the database.

Example

test "create a user" do
  assert_changes(insert: %User{name: "John Doe"}) do
    Accounts.create_user(%{name: "John Doe"})
  end
end

Links

Is this in any way more powerful than making a query directly in the database and checking yourself?

I’m not sure about powerful—you can achieve the same thing with queries—but I’d say it’s much more concise. By asserting on the delta you can make a lot of implicit assertions with very little code.

Let’s say you want to test a function that creates a reply on a forum post (I think I might lack imagination). This function also updates the reply count on the post, which we for some reason cache.

assert_changes(
  insert: %Reply{content: "Lorem ipsum", post_id: ^post_id},
  update: {%Post{id: ^post_id}, reply_count: {0, 1}, updated_at: _}
) do
  Posts.create_reply(%{content: "Lorem ipsum", post_id: post_id})
end

This doesn’t only assert that we inserted a reply and updated the post, it also asserts that:

  • the reply was inserted with the values we expect,
  • reply_count and updated_at were the only fields that were updated on the post,
  • reply_count went from 0 to 1,
  • nothing else was affected.

When not testing the happy path, it generally gets even more concise:

assert_no_changes do
  Posts.create_reply(%{content: nil, post_id: post_id})
end

I’ve used DeltaCheck for a while in a personal project, and I’ve found the tests to be more thorough and consistent, while still being shorter, than before I was using it.

2 Likes

I’ll have to say this seems like an appealing solution to the boilerplate one usually needs and I’m usually rather critical about trying to compare before/after records to each other. Being able to say “I don’t care how this field changed” makes db driven changes less of a hassle. This style of testing certainly couples the tests to the exact db representation of the values though.

2 Likes

Personally, I had some parts of the project where wrong/failed DB operations would introduce inconsistency in the system, so I had to test that all of the entries were correctly inserted/updated, of course there may be other ways to ensure that.

In a more general approach, I totally agree, these kind of tests tend to make subsequent modification of code a hassle.

1 Like