技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> 其他 --> rebar和common_test使用实践和疑惑澄清

rebar和common_test使用实践和疑惑澄清

浏览:2031次  出处信息

rebar是个功能非常强大的Erlang项目管理工具,参看这里 https://github.com/basho/rebar,他的定位是:

rebar is an Erlang build tool that makes it easy to compile and
test Erlang applications, port drivers and releases.

rebar is a self-contained Erlang script, so it’s easy to distribute or even
embed directly in a project. Where possible, rebar uses standard Erlang/OTP
conventions for project structures, thus minimizing the amount of build
configuration work. rebar also provides dependency management, enabling
application writers to easily re-use common libraries from a variety of
locations (git, hg, etc).

common_test是Erlang强大的黑盒测试框架 参见这里

Common Test is a portable application for automated testing. It is suitable for black-box testing of target systems of
any type (i.e. not necessarily implemented in Erlang), as well as for white-box testing of Erlang/OTP programs. Blackbox
testing is performed via standard O&M interfaces (such as SNMP, HTTP, Corba, Telnet, etc) and, if required, via
user specific interfaces (often called test ports). White-box testing of Erlang/OTP programs is easily accomplished by
calling the target API functions directly from the test case functions. Common Test also integrates usage of the OTP
cover tool for code coverage analysis of Erlang/OTP programs.
Common Test executes test suite programs automatically, without operator interaction. Test progress and results is
printed to logs on HTML format, easily browsed with a standard web browser. Common Test also sends notifications
about progress and results via an OTP event manager to event handlers plugged in to the system. This way users can
integrate their own programs for e.g. logging, database storing or supervision with Common Test.
Common Test provides libraries that contain useful support functions to fill various testing needs and requirements.
There is for example support for flexible test declarations by means of so called test specifications. There is also
support for central configuration and control of multiple independent test sessions (towards different target systems)
running in parallel.
Common Test is implemented as a framework based on the OTP Test Server application.

但是common_test由于太强大了,新手使用起来会比较麻烦,经常会碰到些问题,不好解决。

这时候rebar来救助了,它的ct功能把common_test使用的麻烦给解决掉了,让你轻松做测试。
我们先来体验下:

$ mkdir foo
$ cd foo/
$ touch rebar.config
$ rebar create-app appid=foo
==> foo (create-app)
Writing src/foo.app.src
Writing src/foo_app.erl
Writing src/foo_sup.erl
$ rebar  create template=ctsuite
==> foo (create)
Writing test/mymodule_SUITE.erl
$ rebar ct suite=mymodule
==> foo (ct)
DONE. Testing chuba.foo.mymodule_SUITE: TEST COMPLETE, 0 ok, 0 failed, 1 skipped of 1 test cases
$ cd logs
$ hostname -i
10.232.31.89
$ python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...

打卡浏览器 http://10.232.31.89:8000我们可以看到:

\"\"

\"\"

\"\"

上面我们演示了rebar的ct功能使用的基本步骤,底下是进阶信息:
我们从rebar_ct.erl中可以看到:

%% Global options:
%% verbose=1 - show output from the common_test run as it goes
%% suite=\"foo\"\" - runs <test>/foo_SUITE
%% case=\"mycase\" - runs individual test case foo_SUITE:mycase
...
get_ct_config_file(TestDir) ->
    Config = filename:join(TestDir, \"test.config\"),
    case filelib:is_regular(Config) of
        false ->
            \" \";
        true ->
            \" -ct_config \" ++ Config
    end.
...
get_config_file(TestDir) ->
    Config = filename:join(TestDir, \"app.config\"),
    case filelib:is_regular(Config) of
        false ->
            \" \";
        true ->
            \" -config \" ++ Config
    end.

如果test目录下有app.config 那么会把它用-config app.config传给vm, 这个app.config主要用于设置application的环境变量。

如果有test.config, 那么会把它用 -ct_config test.config传给vm, 这个test.config主要用于配置测试案例的变量。

test.config规格是类似这样的,可以参见common_test userguide里面配置的章节:
{key, value}.
{catalog, [{k1,v1}, {k2, v2}]}.

程序里面要用方式获取:
ct:get_config(key).
ct:get_config({catalog,key}).

获取配置的方式有底下几种,是很容易混淆的地方,我来解释下:

test_mymodule(_Config) ->
    io:format(\"port ~p~n\", [ct:get_config({foo, port})]),
    io:format(\"priv_dir ~p~n\", [?config(priv_dir, _Config)]),
    io:format(\"priv_dir ~p~n\", [proplists:get_value(priv_dir, Config)]),
    ok.

?config(key, Config).只是用于读取config变量里面的值,和proplists:get_value(key, Config)是一样的。
看代码:

-define(config,test_server:lookup_config).
lookup_config(Key,Config) ->
    case lists:keysearch(Key,1,Config) of
    {value,{Key,Val}} ->
            Val;
        _ ->
            io:format(\"Could not find element ~p in Config.~n\",[Key]),
            undefined
    end.

现在我们来演示下test.config的使用:

$ pwd
/home/chuba/foo/test
$ cat test.config
{foo, [{hostname, \"127.0.0.1\"},
       {port, 8000}
      ]}.
$ diff mymodule_SUITE.erl mymodule_SUITE.erl.orig
164c164
<     [{require, foo}, {userdata,[{doc,\"Testing the mymodule module\"}]}].
---
>     [{userdata,[{doc,\"Testing the mymodule module\"}]}].
167,168c167
<     io:format(\"port ~p~n\", [ct:get_config({foo, port})]),
<     ok.
---
>     {skip,\"Not implemented.\"}.
$ rebar ct suite=mymodule
==> foo (ct)
DONE. Testing chuba.foo.mymodule_SUITE: TEST COMPLETE, 1 ok, 0 failed of 1 test cases

我们看下现在的执行结果:
\"\"

当然也可以用ct_run来运行:

$ct_run -suite $PWD/mymodule_SUITE -pa $PWD/ebin -logdir $PWD/logs -config test/test.config
Erlang R14B04 (erts-5.8.5) 1 [64-bit] [smp:16:16] [rq:16] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.8.5  (abort with ^G)

Common Test v1.5.5 starting (cwd is /home/chuba/foo)

(ct@my031089)1>
Common Test: Running make in test directories...

CWD set to: \"/home/chuba/foo/logs/ct_run.ct@my031089.2011-10-19_11.52.21\"

TEST INFO: 1 test(s), 1 case(s) in 1 suite(s)

Testing chuba.foo.mymodule_SUITE: Starting test, 1 test cases
Testing chuba.foo.mymodule_SUITE: TEST COMPLETE, 1 ok, 0 failed of 1 test cases

Updating /home/chuba/foo/logs/index.html... done
Updating /home/chuba/foo/logs/all_runs.html... done

我们可以看到ct_run是通过-config foo.config 这样来传配置文件的,这个地方和容易和erl -config app.config混淆。
实际上ct_run是个程序,我们看下他的代码:

//ct_run.c
...
else if (cnt < erl_args) {
            if (strcmp(argv[1], \"-config\") == 0)
                PUSH(\"-ct_config\");
            else if (strcmp(argv[1], \"-decrypt_key\") == 0)
                PUSH(\"-ct_decrypt_key\");
            else if (strcmp(argv[1], \"-decrypt_file\") == 0)
                PUSH(\"-ct_decrypt_file\");
            else
                PUSH(argv[1]);
        }
...

-config选项会被转化成-ct_config来传递给vm,所以和-config app.config就能分开,但是理解起来确实很恼人。

小结: rebar和common_test配合起来用的很爽。

建议继续学习:

  1. Erlang match_spec引擎介绍和应用    (阅读:4528)
  2. whatsapp深度使用Erlang有感    (阅读:4572)
  3. php-erlang    (阅读:4309)
  4. gen_tcp调用进程收到{empty_out_q, Port}消息奇怪行为分析    (阅读:3542)
  5. hibernate使用注意事项    (阅读:3218)
  6. Erlang linkin driver用port_control方式时的一些经验分享    (阅读:2968)
  7. Erlang如何限制节点对集群的访问之net_kernel:allow    (阅读:2971)
  8. ERLANG OTP源码分析 – gen_server    (阅读:2858)
  9. erlang学习手记    (阅读:2697)
  10. gen_tcp容易误用的一点解释    (阅读:2636)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1