[Erlang05]gen_server怎麼去寫eunit?

寫著寫著就懂了發表於2014-05-15

Prework:

  怎樣寫一個基本的Eunit? Doc.

1. 加入標頭檔案:宣告此模組以”_test”結尾的函式都是測試用,並在編譯時自動在這個模組里加入test()函式(當然這個可以用巨集來控制)

-include_lib("eunit/include/eunit.hrl").

2.編寫測試用例:”*_test()”函式":

reverse_nil_test() -> [] = lists:reverse([]).
reverse_one_test() -> [1] = lists:reverse([1]).
reverse_two_test() -> [2,1] = lists:reverse([1,2]).
%%也可以用巨集:這個有好幾種,很方便,要用就看文件,比不用巨集的優勢在於出錯資訊詳細
length_test() -> ?assert(length([1,2,3]) =:= 3).

3. 執行 Eunit

  編譯Module –> 然後:

Module:test().
%%
eunit:test(Module).

以上是一個最簡單的Eunit的例子,那麼:

Question: 類似gen_server有啟動程式類的Eunit怎麼寫?有併發的怎麼寫?

基本Code形式:

-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-compile({no_auto_import, [get/1, put/2]}).

basic_test_() ->
    {setup, 
        fun() -> 
            ?debugFmt("Starting ~p", [?MODULE]),
            case start_link() of
                {error, {already_started, _}} ->
                    ok;
                {ok, _} ->
                    do_stop
            end
        end,
        fun(Stop) -> 
            case Stop of 
                do_stop -> stop();
                ok -> ok 
            end
        end,
        [
            {timeout, 60, fun normal_insert/0},
            {timeout, 60, fun ttl_insert/0}
        ]
    }.
noraml_insert() ->
    todo.
ttl_insert() ->
    todo.
-endif.
Eunit提供以下格式:
%%To make the descriptions simpler, we first list some definitions:
Setup     () -> (R::any())
SetupX     (X::any()) -> (R::any())
Cleanup     (R::any()) -> any()
CleanupX     (X::any(), R::any()) -> any()
Instantiator     ((R::any()) -> Tests) | {with, [AbstractTestFun::((any()) -> any())]}
Where     local | spawn | {spawn, Node::atom()}
Table .1:   (these are explained in more detail further below.)

%%The following representations specify fixture handling for test sets:

{setup, Setup, Tests | Instantiator}
{setup, Setup, Cleanup, Tests | Instantiator}
{setup, Where, Setup, Tests | Instantiator}
{setup, Where, Setup, Cleanup, Tests | Instantiator}
Setup     () -> (R::any())
SetupX     (X::any()) -> (R::any())
Cleanup     (R::any()) -> any()
CleanupX     (X::any(), R::any()) -> any()
Instantiator     ((R::any()) -> Tests) | {with, [AbstractTestFun::((any()) -> any())]}
Where     local | spawn | {spawn, Node::atom()}

我們上面就是用的: {setup,Setup,Cleanup,TestList}這種,所以用Setup啟動,執行TestList後用啟動Setup的返回值傳入Cleanup(Val)結束!注意這個test一定是xxx_test_()的形式,注意最後的_ 

gen_server_enuit

可以看出_test_()的範圍比_test()的大,但是限定為fun() –> end.

Tip: 如果你想用新起程式來測試一個模組【gen_server是不需要這樣子的,本來就是新起了個程式】可以參照Where引數。

通過以上,我們就可以寫出很漂亮的gen_server的enuit函式啦!!

 

那麼如何讓多個enuit並行跑呢?比如不相關的幾個gen_server並行跑起來!

用引數:inparallel

base_test_() ->
    {setup, spawn, 
        fun() -> start() end,
        fun(_) -> stop() end,
        {inparallel, 3,[
            {timeout, 60, funnormal_insert/0},
            {timeout, 60, ttl_insert/0}
        ]}
    }.

驚喜:可以指定同時跑幾個哦,上面指定了3個,不指定也可以的.

========================================================

一個好的application一定要有可靠的測試用例!,但是如果你在程式裡面大量用有副作用的程式字典,還是很難寫enuit的…

相關文章