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:
elm package install
This will create the elm-package.json file with information about your project.
npm install -g elm-test
Then the init command should set up everything for you:
elm test init
And just like that, you are ready to run the tests:
You should see:
Running 7 tests. To reproduce these results, run: elm-test --seed 1509338799
↓ Sample Test Suite
↓ Unit test examples
✗ This test should fail - you should remove it
Failed as expected!
Now go and fix that. You can also get better flow by running the tests in watch mode with
elm test --watch
The init command already created the tree structure and some example specs for you, it should look like that:
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.
Let's look at the first part of tests/Tests.elm examples:
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!
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:
Use BDD Style
It is basically just some alias really, but it does help writing the specs.
To use that, install with elm package:
elm package install rogeriochaves/elm-test-bdd-style
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:
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.
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.
If you got yourself interested on this, start playing with Elm today, and help us improve our tooling.
Feedbacks will be received with love ❤