Testing And Benchmarking in Erlang

Here’s the translation of the Go testing and benchmarking example to Erlang:

-module(int_min).
-export([int_min/2]).
-include_lib("eunit/include/eunit.hrl").

%% Unit testing is an important part of writing principled Erlang programs.
%% The EUnit framework provides the tools we need to write unit tests,
%% and the `rebar3 eunit` command runs tests.

%% We'll be testing this simple implementation of an integer minimum.
int_min(A, B) when A < B -> A;
int_min(_, B) -> B.

%% A test is created by writing a function with a name ending with "_test".
int_min_basic_test() ->
    ?assertEqual(-2, int_min(2, -2)).

%% Writing tests can be repetitive, so it's idiomatic to use a table-driven style,
%% where test inputs and expected outputs are listed in a list and a single function
%% walks over them and performs the test logic.
int_min_table_test_() ->
    Tests = [
        {0, 1, 0},
        {1, 0, 0},
        {2, -2, -2},
        {0, -1, -1},
        {-1, 0, -1}
    ],
    [?_assertEqual(Want, int_min(A, B)) || {A, B, Want} <- Tests].

%% Benchmark tests in Erlang are typically created using the `timer:tc/3` function
%% to measure execution time. Here's a simple benchmark function:
benchmark_int_min() ->
    {Time, _} = timer:tc(fun() ->
        lists:foreach(fun(_) ->
            int_min(1, 2)
        end, lists:seq(1, 1000000))
    end),
    io:format("Benchmark: ~p microseconds~n", [Time]).

To run the tests, you would typically use rebar3 eunit or the Erlang shell:

1> c(int_min).
{ok,int_min}
2> eunit:test(int_min).
  All 6 tests passed.
ok
3> int_min:benchmark_int_min().
Benchmark: 223407 microseconds
ok

In this Erlang version:

  1. We define the module and export the int_min/2 function.
  2. We include the EUnit header file for testing macros.
  3. The int_min/2 function is implemented using pattern matching and guards.
  4. We create a basic test function int_min_basic_test/0.
  5. We implement a table-driven test using a list comprehension and the ?_assertEqual macro.
  6. For benchmarking, we create a benchmark_int_min/0 function that uses timer:tc/3 to measure execution time.

Note that Erlang’s approach to testing and benchmarking is quite different from Go’s:

  • Erlang uses the EUnit framework for unit testing, which is included in OTP.
  • Test functions typically end with _test or _test_.
  • Erlang doesn’t have a built-in benchmarking tool like Go’s testing package, so we implement a simple benchmark using timer:tc/3.
  • The output format and running process are different from Go’s testing package.

Despite these differences, the core concepts of unit testing and benchmarking are still applied in this Erlang example.