2 Biggest ExUnit Improvements in Elixir 1.7

The changes and updates in elixir latest release.

Created using crello.com

This article comprises of two biggest changes of ExUnit.

  • Arguments in the failure report
  • Running mix test with failed flag

1. Arguments in the failure report

We mostly do assertions like

assert is_valid_card(card_type, card_number)

with out using any comparison operators like < > <= == >= inside the unit test cases. Everybody likes being smart. Of course, I do that too.

Personal Experience or impression to write this article:

I have had an experience on the peculiar behaviour of maps with two types of keys allowed to write a map in elixir.

I used a map with binary keys and trying to test them over the map with keys of type atom. Every time I do, the test gets failed. Though I am sending a correct map, being the keys of a different type, it gets failed.

It took me a whole day to figure it out. 🌞

I am always trying to debug the code logic instead of arguments that are passed. If the error report has this feature before, I could have saved a day in my life.

Luckily we are having in the latest release.

The Elixir 1.7 versions are smart enough to tell about the arguments given to the function, here is_valid_card(card_type, card_number)

As a programmer, I don’t like the documented proof. I always prefer the test_cases. Well, let’s test this feature.

Before continuing further, I would like you to know the versions I am using at the moment of writing article.

Elixir and Erlang OTP versions

To test this feature, we will create a project basic_math and a simple function is_valid_card/2 which is completely an idiot one. This is used to check whether the given card_number of card_type is valid or not.

We aren’t much worried to implement the complete logic here. This function, is_valid_card/2 does nothing useful just, it will just judge the length of the card_number based on the card_type.

$ mix new basic_math && cd basic_math

The above shell command creates a new Elixir project and moves your working directory to the basic_math .

Hope, you all knew the project structure. Well in case if you don’t, check out to My First Project in Elixir.

Open the file lib/basic_math.ex and put the following lines of code.

#lib/basic_math.ex
defmodule BasicMath do
def is_valid_card(card_type, card_number) do
case card_type do
:debit ->
card_number
|> Integer.to_charlist()
|> length
|> Kernel.==(12)
       :credit ->
card_number
|> Integer.to_charlist()
|> length
|> Kernel.==(10)
       _ ->
{:error, :invalid_card_type}
end
end
end

After adding the code, the file looks like in the following screenshot…

Quick Docs about the code in basic_math.ex file.

The definition is_valid_card/2 receives two parameters card_type and card_number . We are case matching on card_type . It matches for two case values :credit & :debit and I hope you have understood the rest of the code. It is nothing harder than lifting a 1 gram of stone.

Unit Test Cases

Now, we will write some unit test cases to test our code.

Before using, test the code.

Open the file test/basic_math_test.exs and add the following lines of code

Basic Setup

Add the following code

defmodule BasicMathTest do
use ExUnit.Case
import BasicMath
doctest BasicMath
end

Test Cases for debit card

describe "debit_card" do
     setup do
{:ok, type: :debit, valid_card: 123456789012, invalid_card: 1234567890}
end
     test "valid debit card", %{type: type, valid_card: valid_card} do
assert is_valid_card(type, valid_card)
end
    test "in-valid debit card", %{type: type, invalid_card: invalid_card} do
refute is_valid_card(type, invalid_card)
end
end

Test Cases for Credit card

describe "credit_card" do
setup do
{:ok, type: :credit, valid_card: 123456789012, invalid_card: 1234567890}
end
    test "valid credit card", %{type: type, valid_card: valid_card} do
assert is_valid_card(type, valid_card)
end
    test "in-valid credit card", %{type: type, invalid_card: invalid_card} do
refute is_valid_card(type, invalid_card)
end
end

For the demo purpose, I wrote some test cases to fail on purpose.

The overall file looks like in the following screenshot

basic_math_test.exs

Under the credit_card section, we are using the same setup data used for debit_card unit test cases which eventually results in failure of the test cases.

So, it will now include the value of each argument in the failure report: Let’s check that.

mix test

Run your test cases using the above command. You will see the similar output as in the following screenshot.

mix test … testing the file basic_math.ex

If you observe the above screenshot, Out of four(4), two(2) test cases are failed and you can see the arguments passed to the test case in the failure report.

arguments:

#1
:credit
   #2
123467890

This kinda failure report is very useful when our function is linked with too many functions. It is hard to debug the fail cause of a unit test case when the function is dependent on many other functions. This is where the arguments play the vital role in debugging the code failures.

It is a great healthy feature. 💚

2. Running mix test with failed flag 🚩

When you run the command mix test along with a flag--failed, It runs only the test cases that are failed in your previous attempt of mix test .

It means this time the task mix test --failed don’t execute the successful test cases again. So, we can save the time here.

The failed unit test cases are tracked and cached in a very first mix test

We are having totally 4 unit test cases in the file. But, when you added the failed option, it gives out only 2 failed unit test cases.

You can observe that in the following screenshot.

mix test — failed

Hope you liked it.

Some Of other Artilcles You May Be Interested.

if worth_clappin?, do: CLAP, else: nil

Happy long coding life… :)

Like what you read? Give Blackode a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.