Discover how tests with Elixir work and learn how to write them for robust applications.
When you develop an application, software or other tools, it is necessary to perform tests. Tests are very useful and practical to make sure that your application will work as expected. If certain errors or scenarios are not handled, this could lead to crashes, bugs or even attacks on your applications. This could have huge repercussions and even disastrous consequences. Elixir developers are not exempt from this testing phase. Nevertheless, some Elixir tools facilitate the creation and execution of tests.
It is quite common for tests to be neglected. Indeed, the testing phases represent a cost in time for developers and therefore a financial cost for companies. As a result, development teams are tempted to favor product development, quantity over quality. But tests are really very important when you want to have the most qualitative application possible. In fact, it is recommended to devote about 30% of the development time to testing the various functions of the app. This is not always the case. It is in this context that testing features have been developed on Elixir. The purpose of these features is to facilitate and promote the implementation of tests. This is to help developers in the testing phases of their products by providing them with numerous tools. The testing phase, which is often long and tedious, then becomes more pleasant. All these testing features are implemented in the Elixir ExUnit.
It is not part of the core of Elixir but is an additional tool provided by the language. It does not require any installation and allows to perform unit tests.
When it comes to testing, many different types of tests can be mentioned. However, when it comes to application development, the most common types of tests used by developers are unit tests. Unit tests are essential to ensure that the different parts/portions of the code work properly. One can for example imagine testing a particular function (hence the "unit") etc...
More and more codes are bound to evolve with language versions, updates or added features... These changes can cause unwanted behaviors from your application. This is why unit tests are very practical. Indeed, they will allow you to quickly realize potential problems, for example if a function does not fulfill its role correctly.
On the other hand, unit tests are useful to follow good software engineering practices such as TDD (Test Driven Development). TDD consists in creating a test. At first, it will not work. You will have to develop the desired functionality until the test is passed. This will mean that your function has the expected result. Then rework the function to avoid a too heavy code. Finally rewrite a test to improve the functionality and repeat the previous steps until the functionality is satisfactory.
Unit tests are the foundation of all other tests. This is why they are located at the base of the test pyramid.
Unit tests allow us to test each functionality individually to ensure that it works properly and that the different scenarios that may need to be handled are taken into account. This is what the framework integrated into Elixir will allow us to do: ExUnit.
ExUnit will allow you to test different parts of your code. Although it is not integrated directly into Elixir, it can still be used without any prior installation. The fact that it was developed by the Elixir teams is a big plus because it makes it a tool that is perfectly suited to unit testing in Elixir.
Let's see how it works through an example. We will create an Elixir application, create functions and test them. If you have never used Elixir before, it is advisable to learn the basics by using the online documentation for example.
So we will start by creating an application using the command :
Then we are going to open our file "lib/my_test_app.ex" in this file you should find a "hello" function, we are going to delete this one and create three new ones to compare values. A "higher" function which will return "true" if value 1 is higher than value 2 and "false" otherwise, a "lower" function which will do the opposite and finally an "equal" function which will return true if both values are identical and false otherwise.
You should then have this code :
As you can see these three functions are supposed to compare two values, yet none of them are written in the same way, and all three are correct! The last method is the best way to do this because it requires the least amount of code and is the least complex.
We can now proceed to test these three functions. Let's go to the following location “test/my_test_app_test.exs”. It is from this file that we will be able to test the functions we have written in our “lib/my_test_app.ex” file.
A test is already present in this file but will not work because we have deleted the "hello" function. So this test is useless and can be deleted.
After writing the most obvious tests you might have something like this:
So how does it work? That's what we'll explain in the next part.
As you can see, the first step is to tell the module that you want to use ExUnit.Case. This line of code will simply be used to import the ExUnit test framework.
Then it is recommended to import the module containing our previous functions. This will allow us to call our functions directly without having to write <ModuleName>.<Function>.
Now we can move on to the part we're interested in: the tests!
As you can see on the previous screenshot, it is necessary to first declare the test by simply typing the word "test" followed by a string. This string will describe the test. It is often recommended to indicate which function we want to test, followed by a short description of the test we want to perform. In the previous screenshot, we can see from the descriptions which function we want to test (higher, lower, equal) followed by their arities. The arity of a function is the number of argument(s) that will be passed as parameter. Indeed, specifying the arity of a function in Elixir is important. A function can have a different behavior depending on its number of arguments. Moreover, these descriptions give us information about the expected result. So we understand that in the first test we want to check that the function "higher" returns "true" when the first value passed in parameter is greater than the second. The second and third tests should allow us to check that the function "higher" returns "false". Indeed, the function must return "false" when the first parameter is smaller (second test) or equal (third test) to the second parameter. The following tests work on the same principle but with different expected results.
So we have just described the test we want to perform. Let's now see how to perform this test. To do this, we will have to place ourselves between the "do" and the "end" of our test. Most of the time we will use assertions to check the behavior of our code. An assertion is what we assume will happen. To write an assertion we will have to start by using the macro "assert" followed by the function we want to test followed by a comparator followed by the expected result. In our first test, this gives:
Here we assume that the function "higher" with a value1 greater than value2 will return exactly "true". The same principle applies to all other tests. Although the "assert" macro is the most used, other macros can be used. For example, the "refute" macro which has the opposite behavior of "assert". The list can be found in the official documentation.
In other words, testing is an important part of application development. It allows to have a robust application but also more optimized. Testing helps to avoid problems related to unforeseen cases. It also helps to avoid attacks on the system by closing the doors of entry to malicious individuals. For these reasons, testing should not be neglected. ExUnit is a very interesting tool provided with Elixir since it allows you to easily and efficiently perform unit tests. This makes the experience more user-friendly for users who don't want to spend time on complicated and difficult tests. At Cryptr, we take the time to test our applications in order to ensure that they run smoothly!
So ready to learn more about Elixir and the products we've developed with it? We tell you more at Cryptr.