View Source doctest
A library to test Erlang -moduledoc
and -doc
attributes.
Requirements
OTP >= 27.
Installation
% rebar.config
{profiles, [
{test, [
{deps, [{doctest, "0.6.0"}]}
]}
]}.
Usage
Tests run via the doctest:module/1,2
function or on modules that include the doctest header, but only exported functions are tested.
Testing via doctest:module/1,2 function
Take this module:
-module(foo).
-moduledoc """
Module doc tags can also be tested.
```erlang
1> foo:foo() =:= bar.
true
```
""".
-export([foo/0]).
-doc """
```erlang
1> foo:foo().
foo
```
""".
foo() ->
bar.
Running it via shell:
1> doctest:module(foo).
.F
Failures:
1) doctest:-parse/4-fun-0-/0:13
Failure/Error: ?assertEqual(foo, foo:foo())
expected: foo
got: bar
%% eunit_proc.erl:583:in `eunit_proc:run_group/2`
Output:
Output:
Finished in 0.013 seconds
2 tests, 1 failures
Options
Options can be provided when using the doctest:module/2
function. The available options are:
moduledoc
::boolean()
: enable or disable-moduledoc
testfuns
::boolean()
|[{atom(), arity()}]
: enable or disable-doc
tests or define the functions to be testedeunit
::resolve | term()
: set EUnit options
Testing via doctest header
Take this module:
-module(math).
-export([add/2]).
-ifdef(TEST).
-include_lib("doctest/include/doctest.hrl").
% -doctest <see the options section>.
-endif.
-doc """
Adds two numbers together.
_Example_:
```erlang
1> math:add(0, 1).
1
2> math:add(
.. 1,
.. 1
.. ).
2
```
""".
add(A, B) ->
A+B.
Note that the code is defined like the Erlang shell, starting with
N>
, whereN
is a number, and continues in multiple lines with..
. The result is a value without starting with those shell symbols.
Now, by running rebar3 eunit
:
Finished in 0.018 seconds
2 tests, 0 failures
By changing the first test to:
1> math:add(1, 1).
1
And running rebar3 eunit
again:
Failures:
1) doctest_parse_transform:-parse/4-fun-0-/0:26
Failure/Error: ?assertEqual(1, math:add(1, 1))
expected: 1
got: 2
%% eunit_proc.erl:583:in `eunit_proc:run_group/2`
Output:
Output:
Finished in 0.010 seconds
2 tests, 1 failures
Options
Options are defined via the -doctest
attribute and can be defined multiple times. The available options are:
boolean()
|{enabled, boolean()}
: enable or disable the test running, e.g.:-doctest true.
{moduledoc, boolean()}
: enable or disable-moduledoc
test, e.g.:-doctest {moduledoc, true}.
[{atom(), arity()}]
|{funs, [{atom(), arity()}] | boolean()}
: enable or disable-doc
tests or define the functions to be tested, e.g.:-doctest [add/2].
eunit
::resolve | term()
: set EUnit options, e.g.:-doctest {eunit, resolve}.
map()
: define all or partial options, e.g.:-doctest #{ enabled => true, moduledoc => true, funs => [add/2], eunit => resolve }.
EUnit options
Valid EUnit options are the resolve
atom and a proplist.
By defining resolve
as the EUnit options, doctest
will try to resolve the options via rebar
. Custom options can be defined as documented at rebar3.org:
The default EUnit options can be configured, as documented here.
Interesting undocumented options are:
no_tty
completely disables the default EUnit reporter output{report, {Module, Args}}
runs a custom EUnit reporter (the functionality that prints results to the shell). The reporter module needs the following callbacks implemented:-export([start/0]). -export([start/1]). -export([init/1]). -export([handle_begin/3]). -export([handle_end/3]). -export([handle_cancel/3]). -export([terminate/2]).
no_tty
andreport
can be combined to replace the EUnit reporter with a custom one:{eunit_opts, [no_tty, {report, {my_reporter, Opts}}]}.
TODO
- [ ] More tests
- [ ] Specs
- [ ] Improve docs
Sponsors
If you like this tool, please consider sponsoring me. I'm thankful for your never-ending support :heart:
I also accept coffees :coffee:
Contributing
Issues
Feel free to submit an issue on Github.
License
Copyright (c) 2024 William Fank Thomé
doctest
is 100% open source and community-driven. All components are available under the Apache 2 License on GitHub.
See LICENSE.md for more information.