10

I'm testing the return value of a function. Which of the two is the preferred way?

test "extra verbose, using assert" do
  {:error, reason} = MyModule.my_fun
  assert reason == :nope
end

test "using pattern matching only" do
  {:error, :nope} = MyModule.my_fun
end

I like the first one because, I don't now, a test needs an assert statement and the error message when running the test is more descriptive. Otoh, a MatchError with line number should also be enough.

Carsten
  • 531
  • 4
  • 15

2 Answers2

21

You can use assert with = to get both an assert and a more descriptive error message, and with just one line of code:

assert {:error, :nope} = MyModule.my_fun

Unlike with ==, you can use any pattern on the LHS, although in this case, = can be replaced with == since the LHS is both a valid pattern and value.

On failure, you'll get an error message that's better than just doing the pattern matching without the assert, e.g.

  1) test the truth (MTest)
     test/m_test.exs:10
     match (=) failed
     code:  {:error, :nope} = MyModule.my_fun()
     right: {:error, :nop}
     stacktrace:
       test/m_test.exs:11: (test)
Dogbert
  • 212,659
  • 41
  • 396
  • 397
  • For me the main drawback to using assert on a match is you won't get the left vs right comparison in the test results – Stuart Apr 12 '17 at 08:38
  • Is `assert {:error, :nope} = MyModule.my_fun` really testing anything? If the pattern matches, it will basically assert that the tuple `{:error, :nope}` is truthy, no? If the pattern doesn't match, there's still the `MatchError`. – Carsten Apr 12 '17 at 08:41
  • 2
    @carp nope, there will not be any `MatchError`. `assert` handles `=` specially. I added an example test failure output to the answer just now. – Dogbert Apr 12 '17 at 08:56
  • @Stuart yes, if the LHS is a valid value, I'd use `==` to get that nice colored diff, but if it's not a valid value, this is better than doing just `pattern = value` in the test. – Dogbert Apr 12 '17 at 08:58
  • @Dogbert very true, I guess when asserting atom results the `==` isn't really necessary. Bottom line is always use an assert :) – Stuart Apr 12 '17 at 09:17
1

Whoever comes around this in 2022: consider always using assert, even in conjunction of pattern matching, e.g.:

assert {:error, :nope} = MyModule.my_fun()

Since 1.10, Elixir supports rendering colored diff when pattern matching fails: https://github.com/elixir-lang/elixir/commit/98c6bba436cc4833363295e5fedd3f819504d79d

oldhomemovie
  • 14,621
  • 13
  • 64
  • 99