1

I would like to do high level testing of my mochiweb app, like it is possible to do in Python with WebTest, in Django with the test client and in Ruby on Rails with functional or integration testing. I'm not too picky about how to do it. Basically I would just like to send or simulate HTTP requests and make assertions on the result.

I refactored my code so that my requests handler would not call Req:respond() themselves, but return a tuple {Code, Headers, Body}. This allows me to build dummy requests with mochiweb_request:new(), pass them to my request dispatcher and make assertions on the result using EUnit:

make_request(Method, Path) ->
    Request = mochiweb_request:new(nil, Method, Path, {1, 1},
        mochiweb_headers:make([{"Accept", "text/html"}])),
    Response = myapp:dispatch(Request),
    Response.


signin_test() ->
    {Code, _, _} = make_request('GET', "/signin"),
    ?assertEqual(Code, 200),
    ok.

Now my problem is how to test POST requests. I didn't find anything in mochiweb that would allow me to do that. From reading mochiweb code, it seems that when Req:parse_post() is called, it triggers a read on a socket. I found some interesting test code in src/mochiweb.erl. Apparently this involves building HTTP messages, writing them on a socket and reading the response back. I tried to do this in my own test code but I didn't manage to get anywhere after a few hours. I'm beginning to wonder if I'm going in the right direction. Maybe I need to decouple even more my functionality from the HTTP plumbing, ie. not call Req:parse_post() from within my request handlers. Another solution I'm thinking of would be to use a third-party web testing library, not necessary written in Erlang. Maybe something in Ruby or Python or even maybe Selenium.

So what solution would you recommend to do functional or integration testing of a mochiweb app?

Alex Marandon
  • 4,034
  • 2
  • 17
  • 21

3 Answers3

1

We mostly decouple our tests from the HTTP plumbing. Usually the right thing to do in a functional environment anyway.

There is some eunit code in src/mochiweb_multipart.erl that is probably more relevant to your particular use case.

  • I don't understand what you mean by "decouple our tests from the HTTP plumbing". When I said "decouple even more my functionality from the HTTP plumbing", I meant that my controllers would for instance not call Req:parse_post() themselves but would be provided with parsed POST data as an Erlang data structure by a function higher up in the call stack. That function dealing with "HTTP plumbing" would not be tested. Only the request handlers would be tested by passing them Erlang data structures containing POST data. Is it what you do as well? – Alex Marandon Jan 01 '11 at 11:18
  • I had a look at src/mochiweb_multipart.erl eunit code and I think I roughly understand what it does. In this code you define a ServerFun yourself in order to test functionalities of mochiweb. In my case I would like to test existing server functionality so I suppose I should provide one of my app functions as the loop option that mochiweb_socket_server:start() takes? Could it be the loop function defined in mochiweb skeleton app? (I tried and it didn't work, but it's quite possible that I had a problem elsewhere in my code). – Alex Marandon Jan 01 '11 at 11:26
  • Yes, sorry about not being more specific. Having decoupled tests from the HTTP plumbing implies that the functionality itself is decoupled from the HTTP plumbing. – YOUR ARGUMENT IS VALID Jan 01 '11 at 13:51
0

Why don't you just use an http client to make the calls? I use ibrowse to system test my webmachine server, including POSTing data as needed.

mwt
  • 135
  • 6
0

i use the common test server and for testing i use ibrowse. Here is an example :

post_cap_query_no_caps(_Config) ->
A="<?xml version=\"1.0\" encoding=\"utf-8\"?><query><capabilities/></query>",
{ok, "200", _C, Body}=ibrowse:send_req("http://localhost:8000/devices",  XML_CONTENT_TYPE, post, A),
"<devices/>" == Body.
Ulf
  • 96
  • 5
  • Thank you for pointing ibrowse. Did you manage to get it to work well with eunit? Do you start/stop the server and setup a test environment using eunit fixtures facility? – Alex Marandon Jan 01 '11 at 10:59