this repo has no description
1+++ 2title = "Common Test for Elixir developers" 3date = 2019-07-15 4 5[taxonomies] 6tags = [ 7 "beam", 8 "testing" 9] 10 11[[extra.thanks]] 12name = "José Valim" 13why = "for reading it through and reviewing before publishing" 14+++ 15 16In my new job I have opportunity to work a little bit more with Erlang code and 17Erlang related tools than earlier. That forced me a little to learn and use 18[Common Test][ct] library which is **the** testing library in Erlang world. 19When after that I needed to work back it hit me hard how much stuff I am 20missing in Elixir. In this article I will try to present Common Test library 21from the viewpoint of long standing Elixir guy and present how it compares to 22the ExUnit. 23 24## Unit testing vs integration testing 25 26The main difference between these two is their intended usage. In it's core 27ExUnit is intended as a library for unit testing (no surprise there, as it is 28literally in it's name), on the other hand Common Test is more about integration 29testing and looking on the system as a whole. So the discussion there would not 30be fair, as it isn't apples to apples, but for second let's check what makes 31each of them great for their intended uses: 32 33ExUnit for unit testing: 34 35- Simple way to setup and teardown tests via `setup` and `setup_all` macros 36- Built in testing of documentation examples via `doctest` 37- Immutability of test environment (at least that is what you should try to 38 achieve) 39- Very simple way of running different test modules in parallel (tests within 40 single module are always sync) 41- Each test run in separate process, which prevents sharing data between 42 processes via process dictionary 43- Grouping tests into `describe` blocks 44- In overall simplicity of the library as a whole 45 46Common Test for integration testing: 47 48- Persistent test results - logs, results, "generated garbage" is stored between 49 runs in the Common Test, which allows to track what and when happened, and if 50 needed trace the bug in the logs/leftovers 51- Generating "private directory" per suite 52- Grouping tests while allowing single test to be reused in different groups 53- Extensive control about order and parallelization of tests within groups 54- Built in very extensive and detailed reports (HTML and JUnit) 55- Distributed testing 56- Define dependencies between tests 57- Set of helpers for working with different network protocols (SSH, Telnet, 58 SNMP, FTP, Erlang RPC, netconf) 59- Built in support for data fixtures 60- Built in support for complex configuration of test runs via [test 61 specifications](http://erlang.org/doc/apps/common_test/run_test_chapter.html#test-specifications) 62- Built in logging (we will cover that later) 63 64So as you can see, the Common Test is much broader and complex, but at the same 65time it provides a lot of utilities that are really helpful while writing 66integration tests, that can span multiple applications. 67 68## Writing Common Test suite 69 70While CT provides enormous power in hand of the experienced tester/developer 71it's API isn't the top of the class (which happen a lot in Erlang tools, whoever 72wanted to integrate them with anything then they will know what I mean). But in 73fact writing simple test suite in CT is fairly easy: 74 75```erlang 76-module(example_SUITE). % The naming convention (with uppercase _SUITE) Erlang 77 % convention which allow ct to find test suites. 78 % Something like ExUnit _test.exs naming convention 79 80-export([all/0]). 81 82-export([test_function_name/1]). 83 84all() -> 85 [test_function_name]. 86 87test_function_name(_Config) -> 88 2 = 1 + 1. 89``` 90 91It is pretty easy and understandable format, but with due CT power it [quickly 92can grow to be "less" readable](https://github.com/erlang/otp/blob/81d332cc693d2be8a5af16bfbcae0bfde6702479/lib/ssh/test/ssh_algorithms_SUITE.erl#L36). 93Taming that power can be problematic and can cause few headaches for newcomers. 94 95## Reporting 96 97Another part, and the one that I miss the most in ExUnit, is reporting in Common 98Test. This alone is in my humble opinion **THE** best part of the library. To 99present you how this work assume that we have above test suite which we will run 100with `ct_run -dir .`. This will compile and run our tests (obviously), but in 101addition to that it will generate hell lot of cruft files, some JQuery (yes, 102this is still used in 2019), some CSS files, some HTML and other. 103 104Just check [this out](/common-test-example/simple/index.html). This is example report 105generated by the Common Test. As you can see it contains a lot of information in 106quite readable format. Not only it contains information about current run, but 107all previous runs as well, which is really handy when tracking regressions. 108 109But can we store even more information there? Yes, as CT includes simple 110logging facility it is completely possible to log your own information during 111tests, for example, lets modify our test to log some information: 112 113```erlang 114test_function_name(_Config) -> 115 ct:log("Example message"), 116 2 = 1 + 1. 117``` 118 119Now when we run tests again, then we will see more information (even coloured) 120in [our test log](/common-test-example/log/ct_run.ct@NiunioBook.2019-07-16_11.03.21/common-test-example.log.logs/run.2019-07-16_11.03.22/example_suite.test_function_name.html): 121 122![Common Test log "Example message" on green background](/img/common-test/log.png) 123 124Additionally there is support Surefire XML output (commonly known as JUnit XML) 125via [hook that is distributed with Common Test](http://erlang.org/doc/apps/common_test/ct_hooks_chapter.html#built-in-cths). 126This is very useful, as many CI services (for sure Jenkins, Circle CI, and 127GitLab CI) support such files to provide better CI results than raw stdout. 128 129## Comparison to ExUnit 130 131ExUnit is great tool, which is very flexible while being relatively simple. 132Unfortunately that simplicity makes it very lacking when comparing with "more 133established" solutions like Common Test which shines when we "grow out" of the 134ExUnit tests. It provides a lot great tools that really help with finding bugs 135(for example when I was joining the project and I was trying to run tests 136locally I have some issues due to misconfiguration, it was much easier to send 137tarball of the test results instead of sending wall of text captured from 138stdout). 139 140Don't get me wrong, ExUnit is great and powerful, and for sure you should use 141it. It is great evolution over EUnit, but again, it would be worth of having 142built in [Surefire XML output](http://www.erlang.org/doc/man/eunit_surefire.html) 143due to it's popularity and support in many CI services. 144 145## Future 146 147But is everything lost and we need to fall back to the Erlang code (which can be 148problematic for many people) to use Common Test? Not exactly, Comcast (yes, that 149Comcast) [created simple wrapper][ctex] for Elixir (unfortunately seems pretty 150dead to me) and I have started [Commoner][commoner] library that is meant to 151provide API more familiar and easier to use: 152 153```elixir 154defmodule Commoner.ExampleSuite do 155 use CommonTest.Suite 156 157 test "foo bar" do 158 assert (1 + 1) in [2] 159 end 160 161 test "bar baz" do 162 CommonTest.log("Hello") 163 end 164end 165``` 166 167I am very interested about your feelings about Common Test usage in Elixir and 168about proposed API for Commoner. You can ping me: 169 170- On [Elixir forum thread about Commoner][forum] 171- On Twitter via `@hauleth` 172 173[ct]: http://erlang.org/doc/apps/common_test/basics_chapter.html 174[ctex]: https://github.com/Comcast/ctex 175[commoner]: https://github.com/hauleth/commoner 176[forum]: https://elixirforum.com/t/commoner-elixir-wrapper-for-common-test-library/23966?u=hauleth