I've got an application where I cast a message to a gen_server to start an operation, then I call the gen_server every second to gather intermediate results until the operation completes. In production, it usually takes a couple of minutes, but it's only limited by the input size and I'd like to test hour long operations, too.
I want to always make sure this operation stil开发者_StackOverflow中文版l works by running a test as needed. Ideally, I'd like to run this test multiple times with different inputs, also.
I use eunit right now, but it doesn't seem to have a purpose-built way of exercising this scenario. Does commmon test provide for this? Is there an elegant way of testing this or should I just hack something up? In general, I'm having trouble wrapping my head around how to systematically test stateful, asynchronous operations in Erlang.
Yes, common test will do this.
This is a cut down version of the common test suite skeleton that our erlang emacs mode provides (you can use the normal erlang one or erlware one):
-module(junk).
%% Note: This directive should only be used in test suites.
-compile(export_all).
-include("test_server.hrl").
%%
%% set up for the suite...
%%
init_per_suite(Config) ->
Config.
end_per_suite(_Config) ->
ok.
%%
%% setup for each case in the suite - can know which test case it is in
init_per_testcase(_TestCase, Config) ->
Config.
end_per_testcase(_TestCase, _Config) ->
ok.
%%
%% allows the suite to be programmatically managed
%%
all(doc) ->
["Describe the main purpose of this suite"];
all(suite) ->
[].
%% Test cases starts here.
%%--------------------------------------------------------------------
test_case(doc) ->
["Describe the main purpose of test case"];
test_case(suite) ->
[];
test_case(Config) when is_list(Config) ->
ok.
There are 2 basic ways you could do it.
First up start the gen_server in init_per_suite/1
and then have a large number of atomic tests that act on that long running server and then tear the gen_server down in end_per_suite/1
. This is the preferred way - your gen_server should be long-running and persistent over many transactions, blah-blah...
The other way is to make a singleton test and start the gen_server with init_per_testcase/2
and tear it down in end_per_testcase/2
Testing Stateful Asynchronous operations is hard in any language, Erlang or otherwise.
I would actuall recommend using etap and have the asynchronous tests run a callback that will then run etap:end_tests()
Since etap uses a running test server and it waits for the end_test call you have a little more control for asynchronous tests.
精彩评论