Erlang测试 #

一、EUnit #

1.1 基本测试 #

erlang
-module(my_module).
-include_lib("eunit/include/eunit.hrl").

add_test() ->
    2 = my_module:add(1, 1).

add_test_() ->
    [
        ?_assertEqual(2, my_module:add(1, 1)),
        ?_assertEqual(0, my_module:add(-1, 1)),
        ?_assertEqual(5, my_module:add(2, 3))
    ].

1.2 断言宏 #

说明
?assert(Expr) 断言为真
?assertNot(Expr) 断言为假
?assertEqual(A, B) 断言相等
?assertNotEqual(A, B) 断言不等
?assertMatch(Pattern, Expr) 断言匹配
?assertException(Class, Pattern, Expr) 断言异常
?assertError(Pattern, Expr) 断言错误
?assertThrow(Pattern, Expr) 断言抛出
?assertExit(Pattern, Expr) 断言退出

1.3 测试生成器 #

erlang
-module(generator_test).
-include_lib("eunit/include/eunit.hrl").

add_test_() ->
    [
        {"Add positive numbers", ?_assertEqual(3, add(1, 2))},
        {"Add negative numbers", ?_assertEqual(-3, add(-1, -2))},
        {"Add zero", ?_assertEqual(1, add(1, 0))}
    ].

add(A, B) -> A + B.

1.4 运行测试 #

bash
rebar3 eunit

或在Shell中:

erlang
eunit:test(my_module).

二、Common Test #

2.1 测试套件结构 #

erlang
-module(my_SUITE).
-include_lib("common_test/include/ct.hrl").

-export([all/0, init_per_suite/1, end_per_suite/1]).
-export([test_case_1/1, test_case_2/1]).

all() -> [test_case_1, test_case_2].

init_per_suite(Config) ->
    Config.

end_per_suite(_Config) ->
    ok.

test_case_1(_Config) ->
    2 = 1 + 1.

test_case_2(_Config) ->
    ok = ok.

2.2 测试配置 #

text
my_app/
├── test/
│   ├── my_SUITE.erl
│   └── my_app_SUITE_data/
│       └── config.txt

2.3 测试规格 #

erlang
{suite, my_SUITE}.
{testcase, test_case_1}.

2.4 运行测试 #

bash
rebar3 ct

或:

bash
ct_run -suite my_SUITE

三、测试模式 #

3.1 单元测试 #

erlang
-module(unit_test).
-include_lib("eunit/include/eunit.hrl").

reverse_test() ->
    [] = lists:reverse([]),
    [1] = lists:reverse([1]),
    [3, 2, 1] = lists:reverse([1, 2, 3]).

3.2 集成测试 #

erlang
-module(integration_test).
-include_lib("common_test/include/ct.hrl").

-export([all/0, init_per_suite/1, end_per_suite/1]).
-export([start_stop_test/1]).

all() -> [start_stop_test].

init_per_suite(Config) ->
    {ok, Pid} = my_server:start_link(),
    [{server, Pid} | Config].

end_per_suite(Config) ->
    Pid = ?config(server, Config),
    my_server:stop(Pid).

start_stop_test(Config) ->
    Pid = ?config(server, Config),
    true = is_process_alive(Pid).

3.3 属性测试 #

erlang
-module(prop_test).
-include_lib("proper/include/proper.hrl").

prop_reverse() ->
    ?FORALL(L, list(integer()),
        lists:reverse(lists:reverse(L)) =:= L).

四、Mock #

4.1 使用meck #

erlang
-module(meck_test).
-include_lib("eunit/include/eunit.hrl").

mock_test() ->
    meck:new(my_module),
    meck:expect(my_module, func, fun() -> mocked end),
    ?assertEqual(mocked, my_module:func()),
    meck:unload(my_module).

五、最佳实践 #

5.1 测试命名 #

erlang
add_positive_numbers_test() -> ok.
add_negative_numbers_test() -> ok.

5.2 测试隔离 #

erlang
init_per_testcase(_TestCase, Config) ->
    Config.

end_per_testcase(_TestCase, _Config) ->
    ok.

5.3 测试覆盖 #

bash
rebar3 cover

六、总结 #

本章学习了:

  • EUnit单元测试
  • Common Test集成测试
  • 测试模式
  • Mock使用
  • 最佳实践
最后更新:2026-03-27