2 Biggest ExUnit Improvements in Elixir 1.7
Tags: elixir, testing, elixir17, exunit
Published: 2018-07-29 11:22:06

---
title: 2 Biggest ExUnit Improvements in Elixir 1.7
published: true
description: This article comprises of two biggest changes of ExUnit.
tags: [elixir, testing, elixir1.7, ExUnit] 
---

![Created using crello.com](https://cdn-images-1.medium.com/max/2048/1*RKP2KBCHBNoDf3V_1_JlcQ.jpeg)


- 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](https://cdn-images-1.medium.com/max/8576/1*tHDoidj5NGMYz6ost2pwKQ.png)***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`.

```shell
 $ mix new basic_math && cd basic_math
```

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](https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html#our-first-project).

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

```elixir

#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…

![](https://cdn-images-1.medium.com/max/2808/1*wpLmHTLkFpoo7pBneNioXA.png)

### 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

```elixir
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**

```elixir
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 purposely wrote some test cases to fail.

The overall file looks like in the following screenshot

![basic_math_test.exs](https://cdn-images-1.medium.com/max/3796/1*q4J3Mt8u9_cfBe-dDYvc3A.png)*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.

```shell
$ 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](https://cdn-images-1.medium.com/max/3840/1*SlPz6vBSKVjYfy_84OMpRQ.png)*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 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 — failed](https://cdn-images-1.medium.com/max/2000/1*39Qx0qT-tikAADaBFcpRCQ.png)*mix test — failed*

Hope you liked it.

Happy long coding life… :)