EWTS - Erlang Web Test Suite

Erlang Web Test Suite is an optional application which has been created in order to make the testing phase easier and faster.

EWTS makes use of:

Usage

In order to test his application(s) user should do the following:

Helper functions

Since Erlang Web provides an easy to extend server interface layer (currently Inets, Yaws and EWGI callback modules are implemented), EWTS is shipped with two modules e_mod_ewts - emulating the web server layer - and ewts_client - emulating a client's browser. Thanks to that approach it is possible to simulate the browser-server interaction automatically.

In his test functions the test developer should use the ewts_client helper to emulate the client's browser. The emulator can be "run" in two modes: stateless and stateful. In the first mode server's cookie is not shared between requests: the test implementation have to take care of that by itself. The latter one keeps track of the cookie. In order to use stateless mode in the client, user should call direct equivalent of the FUN_NAME: direct_FUN_NAME (for example instead of calling stateful request/1 user should call stateless direct_request/1).

The following functions have been implemented to make user's life easier:

function

description

example

request(Url)

performs GET request to the given Url (without any arguments)

ewts_client:request("/blog/read/4"))

request(Url, GetArgs)

performs GET request to the given Url

ewts_client:request("/blog/read/4", [{"collapse_comments", "true"}])

request(Url, GetArgs, PostArgs)

performs POST request to the given Url

ewts_client:request("/blog/comment", [], [{"author", "Winnie the Pooh"}, {"body", "I am banana!"}])

request(Url, GetArgs, PostArgs, Cookies)

performs request to the given Url

ewts_client:request("/blog/my_page", [], [], [{"my_blog_cookie", "deadbeef"}])

request(Url, GetArgs, PostArgs, Cookies, Protocol) 

performs request to the given Url using selected protocol (http or https)

ewts_client("/blog/signin", [], [{"username", "michal"}, {"password", "qwerty"}], [], https)

Request's helper functions return the response record, which consists of the following fields:

field

description

example

headers

headers returned from the server

[{"Set-cookie", "my_blog=2432142323"}, {"Server", "e_mod_ewts 1.0"}]

code

response code

200

cookies

cookies returned from the server

[{"my_blog_cookie", "deadbeef"}]

body

response body

"<html><body><h1>Hello!</h1></body></html>"

req_dict

request dictionary of the request

[{"__path", "/blog/read/2"}, {"my_var_1", 42}]

The response record definition can be found in "ewts-VSN/include/request.hrl".

Note that cookies have been separated from the other headers because of the frequent usage.

Dbg aspect extension

Because EWTS has not been designed to act as a blackbox test tool, it comes up with a new testing approach. Since Erlang's trace tool has enormous potential, we decided to make use of it in the Erlang Web Test Suite application.

Let's imagine you can specify, in a declarative way, which functions within your application should be called and what should be their results. For example, if you visit "/blog/read/4" you want the following functions to be called:

Without changing your source code it is impossible to check the return values of those functions. And here comes the ewts_dbg extension. If you want to check those function you should at first register them in your checker:

   1 ewts_dbg:clear(),
   2 ewts_dbg:add_case({function_response, {blog, read, 1}, {template, "blog/note.html"}}),
   3 ewts_dbg:add_case({function_response, {wtype_blog, read_note, 1}, [#blog_note{id=4, title="my note", body="my note's body"}]}),
   4 ewts_dbg:add_case({function_response, {wpart_blog, render_widget, 2}, "<div><h1>My note</h1><p>my note's body</p><div>"}),

The rest of the test scenario should be implemented, using ewts_client:request call. Then, the additional eunit DBG macro should be triggered: ?assertDbg(ewts_dbg:results(), MinTestsPassed) after all the eunit test. That macro will retrieve all events caught by ewts_dbg and compare their number with the minimum number of events that should have happened (in our example, if you want all of them to happen, provide 3 as MinTestsPassed). In some cases it might be useful to provide multiple checks and mark test as passed if only some of them succeed.

As you might have noticed, the following syntax is correct for the ewts_dbg:add_case/1 function: ewts_dbg:add_case({function_response, {Mod, Fun, Arity}, Response}) where Mod, Fun are atoms, Arity is an integer and Response is any arbitrary term.

ewts_dbg:clear/0 is used to clear all the cases and their history.

Cover reports

Erlang/OTP package contains a great tool for checking the code coverage: it's called cover and is a part of tools application. At the end of all test suites, EWTS generates the summary pages which show which parts of the code have been covered with tests. The report can be found in the $PROJECT_ROOT/doc/ewts_report directory.

myapp example application

In order to demonstrate the EWTS usage, myapp example application has been implemented. It is available as an ecomponent. In order to download it, user must type:

./bin/e_component.erl install myapp-0.1

The application needs a proper initialization. In order to init the database, start an Erlang node (/bin/start_interactive) and run wtype_widget_test:install() (note that the mnesia's schema must be present). Then copy myapp/priv/dispatch.conf to the config directory and myapp/priv/templates/* to the templates directory.

There are several tests implemented: rendering all basic types widgets and CRUD operations on model.

After running ./bin/test.erl, the output should look like:

  All 10 tests successful.
EWTS: All tests passed.  97% line coverage.
EWTS: You totally stormed that level! Let's see if you can storm the next...

EWTS (last edited 2009-10-19 12:23:34 by BartlomiejPuzon)