Assertions - helpful assertions to help you write better tests

This looks very useful! I think it makes sense to use this as an additional base library and then write/name your own assertions on top of it. For example I use this function extensively in my tests:

  @doc """
  Helper for checking that for two structs, or two lists of structs have the
  same id keys
  """
  def assert_ids_match(list1, list2) when is_list(list1) and is_list(list2) do
    list1_ids =
      list1
      |> Enum.map(fn
        %{id: id} -> id
        nil -> nil
      end)
      |> Enum.sort()

    list2_ids =
      list2
      |> Enum.map(fn
        %{id: id} -> id
        nil -> nil
      end)
      |> Enum.sort()

    assert list1_ids == list2_ids
  end

  def assert_ids_match(%{id: id1}, %{id: id2}) do
    assert id1 == id2
  end

And with your assertions library it would look something more like:

import Assertions

def assert_ids_match(left, right) when is_list(left) and is_list(right) do
  assert_lists_equal(left, right, &assert_ids_match/2)
end

def assert_ids_match(%{id: left_id}, %{id: right_id}) do
  assert left_id == right_id
end

I do have a few quibbles with the naming of a few checks. For example I think that assert!/1 would be better named as assert_true or assert_equals_true to make it more obvious that it is checking that the value is exactly equal true (and not just truth). Although a simple assert expression == true is what I would probably still use.

But what I would really like would be a solution that would let you write a test like (where pin operator is used in the same fashion as ecto queries):

result = some_function(data)
assert_pin_match %{id: ^data.id, name: ^original.name} = result

(I talk about this more at Can you pin a temporary variable while asserting a pattern match)

1 Like