7
votes

In a simple Erlang YAWS-based RESTful application I would like to have a set of tests that send HTTP requests to a RESTful API, get responses from the server and then test those responses.

It would be nice if each "send-request-get-request-test" test could be run from within EUnit (making possible to use test generators).

I would also like to be able to run this set of tests with rebar (make test).

Recently I used ibrowse in another application (Mochiweb), but I found it quiet cumbersome to use.

Are there any other options to write Erlang/OTP tests that can send HTTP requests to a YAWS RESTful application? What is the most common way to do that?

3

3 Answers

6
votes

Did you try etest and especially etest_http?

5
votes

I use common_test with ibrowse for testing REST based services.

  1. It's part of erlang distribution
  2. You can call the tests from rebar
  3. You can configure your tests, so the run in parallel, sequencies ....

Have a look at this presentation : http://www.erlang-factory.com/upload/presentations/275/CommonTestPresentation.pdf

4
votes

You could use Tsung, but this is what i would do: I would write a massively threaded tester using a good HTTP Client like curl, or ibrowse running from a different machine. and then test depending on what i want.

EDIT


%% To ensure that Ibrowse is started
ensure_ibrowse()-> case whereis(ibrowse) of undefined -> ibrowse:start(); Any when is_pid(Any)-> ok end.
%% To make a get request
do_get(Link)-> try ibrowse:send_req(Link,[],get) of {ok,_,_,Result} -> %% Result could be JSON in which case you would %% mochijson2:decode(Result) Other -> {error,Other} catch E1:E2 -> {exception,{E1,E2}} end.
%% To save response to a file
save_to_file(Link)-> try ibrowse:send_req(Link,[],get,[],[{save_response_to_file,true}]) of {ok,_,_,{file,FilePath}} -> %% Do anything with the file, %% ------------------------------------------------------- %% like {ok,FileHandle} = file:open(FilePath,[read]) %% ----------------------------------------------------- %% OR {ok,Contents} = file:read_file(FilePath) %% ------------------------------------------------------- %% OR if the response is a .zip file %% {ok,FileList} = zip:unzip(FilePath), %% [begin process_file_contents(element(2,file:read_file(F))) end || F <- FileList] %% --------------------------------------------------------------------------------
Other -> {error,Other} catch E1:E2 -> {exception,{E1,E2}} end.
%% To make a POST %% Usually, if you use mochijson to encode erlang terms %% to JSON, you will:: %% JSON = lists:flatten(mochijson:encode({struct,[Terms]}))
post(Link,JSON) -> try ibrowse:send_req(Link,[],post,JSON,[]) of {_,_,_,Result} -> try mochijson2:decode(Result) of {struct,[{<<"key1">>,<<"value1">>},...]} ->
%% proceed here JSONOther -> {error,JSONOther} catch R:R2 -> {exception,{R:R2}} end; Any -> erlang:throw({write_failed,Link,Any}) catch E1:E2 -> {exception,{E1,E2}} end.
%% To make a put request %% same as Post, just change the atom 'post' to 'put'

%% To add headers to a request
post(Link,JSON)-> Headers = [{"Content-Type","application/json"}], try ibrowse:send_req(Link,Headers,post,JSON,[]) of
{_,_,_,Result} -> try mochijson2:decode(Result) of {struct,[{<<"key1">>,<<"value1">>},...]} ->
%% proceed here JSONOther -> {error,JSONOther} catch R:R2 -> {exception,{R:R2}} end; Any -> erlang:throw({write_failed,Link,Any}) catch E1:E2 -> {exception,{E1,E2}} end.