Testing in Elm
May 19: update to Elm 0.17
Nov 21: update to Elm 0.18
Elm is a great language with an awesome compiler, basically, if your code compiles, the chances are that it has zero runtime exceptions.
But, although your code will run, you must also assure that it behaves as you expect, ensuring things that the compiler won’t. We can go even further, with fuzz testing, but more on that later.
Testing with elm-test
ElmTest is the unit test library for Elm, let’s use that. First, create a new project:
mkdir test-example
cd test-example
elm package install
This will create the elm-package.json file with information about your project.
Previously, this article explained how to setup your tests, but now there is a JavaScript CLI for elm-test that made the setup easier than ever.
Install elm-test:
1 | npm install -g elm-test |
Then the init command should set up everything for you:
1 | elm test init |
And just like that, you are ready to run the tests:
1 | elm test |
You should see:
1 | elm-test |
Now go and fix that. You can also get better flow by running the tests in watch mode with elm test --watch
Tree structure
The init command already created the tree structure and some example specs for you, it should look like that:
1 | . |
The Main.elm file is the one that includes all your other tests to be ran.
You should also have noted that it created a second elm-package.json inside the tests folder. This is a good practice in order to have your test dependencies separated from your source dependencies.
Writing Tests
Let’s look at the first part of tests/Tests.elm examples:
1 | module Tests exposing (..) |
This has basically all you need for writing elm unit tests. Tests are composed of a describe
which join a list of tests
, which only have one expectation each.
As you can see in the first line module Test
, this is just an elm module like any other. You can rename it if you want. Also, you can nest describe
statements. So, it is easy to split your tests to match your src
structure and then join them all together with a final describe
. Try it!
Fuzz Testing
ElmTest also comes with a great feature which is Fuzz Testing, also known as property-based tests, generative tests, or QuickCheck-style tests.
The problem is that with simple unit tests you usually give just a few examples to test the output, and you can forget to test some case. With fuzz testing you can generate about 100 different inputs to check if your function fits for all the cases.
For testing with fuzz, you’ll need a fuzzer, which is something that produces random values. ElmTest already comes with some for generating random lists, ints, strings, and others. You can use them like this:
1 | all : Test |
Use BDD Style
So, I’ve been testing my JavaScript code for a good amount of time now, and I really like the way your tests in something like chai or jasmine ends up being very descriptive and idiomatic, so I’ve created the elm-test-bdd-styleon top of elm-test.
It is basically just some alias really, but it does help writing the specs.
To use that, install with elm package:
1 | cd tests |
Now if you import ElmTestBDDStyle, you can use it instead of test, and expect … toBe instead of |> Expect
. I’ve also removed the need for passing a function when not fuzz testing.
So we can rewrite out Tests.elm like this:
1 | module Tests exposing (..) |
It is a little more readable in my humble opinion.
Where to go next
There are some other toolings for help with elm testing, for example elm-testable allows you to test Effects and Tasks, elm-webdriver allows you to control selenium with elm for writing end-to-end tests, and lobo is an alternative elm-test runner.
There is also the #test
channel on elm’s community slack were you will find help to test your elm code and also people willing to improve elm testing tooling.
Conclusion
We now have all the tools we need to build a fully tested Elm code, this combined with Elm powerful compiler will make it very hard for any bugs to pass by.
Although we don’t have all the tools purely on Elm right now, we can use some JavaScript or even other languages tooling to help with the development like I showed. For end-to-end tests for example you can also use Capybara or WebdriverIO which are great tools.
If you got yourself interested on this, start playing with Elm today, and help us improve our tooling.
Feedbacks will be received with love ❤
Comments
If you’d like to add a comment, please send a merge request adding your comment here, copying this block as an example
Comments
If you’d like to add a comment, please send a merge request adding your comment here, copying this block as an example