DEV Community

blackode
blackode

Posted on

2 Biggest ExUnit Improvements in Elixir 1.7

Created using crello.com

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

1. Arguments in the failure report

We mostly do assertions like

assert is_valid_card(card_type, card_number)

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

Personal Experience or impression to write this article:

I have had an experience on the peculiar behavior 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 a map with keys of type atom. Every time I do, the test gets failed. Though I am sending a correct map, being the keys are 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**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. The 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
Enter fullscreen mode Exit fullscreen mode

The above shell command creates a new Elixir project and changes your current 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
Enter fullscreen mode Exit fullscreen mode

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. Nothing like that, I am just kidding.

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

The overall file looks like in the following screenshot

basic_math_test.exsbasic_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
Enter fullscreen mode Exit fullscreen mode

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.exmix 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
Enter fullscreen mode Exit fullscreen mode

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 a 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 — failedmix test — failed

Hope you liked it.

Happy long coding life… :)

Top comments (0)