Yesterday i was forced to write a functional test for a HTTP auth secured action. Pretty easy i thought, but it took me hours for finding the correct lines.
The HTTP auth mechanism works like it is explained in the blog post HTTP authentication with sfGuard, although the sfGuard plugin is not used in our application.
This secure action takes the PHP_AUTH_USER and PHP_AUTH_PW $_SERVER variable and validates it. If the validation passes, a redirect to the called uri is executed.
How does a functional test look like?
Thanks to the setAuth method of the browser test class, we can simulate an incoming request with HTTP auth data pretty easy. This authentication will last for the very next request, subsequent requests have to be authenticated again.
After calling the setAuth method, we can call some action as usual.
1 2 3 4 | $browser->setAuth($username, $password)-> // call an HTTP Auth secured action get( '/some_module/some_action' ); |
Now we have reached the tricky part. Due to the secured action, the request is first of all forwarded to the defined secure action, here it is the login action of the auth module. Within this action, a redirect is called to the original uri.
This means, that the next simple test code will fail:
1 2 3 4 5 6 7 8 9 | $browser->setAuth($username, $password)-> // call an HTTP Auth secured action get( '/some_module/some_action' )-> with('request')->begin()-> isParameter('module', 'some_module')-> isParameter('action', 'some_action')-> end()-> |
The current module is not the original called some_module one, but the auth one. This process could be tested with the isForwardedTo method.
If we would check the response at this point, we won’t get the correct response, but a redirection statement:
1 | <html><head><meta http-equiv="refresh" content="..."/></head></html> |
Handling this redirect, needs two more method calls in the test code. After adding the methods isRedirected and followRedirect we have everything we need to provide a good test for this process.
The complete test code looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | $browser->setAuth($username, $password)-> // call an HTTP Auth secured action get('/some_module/some_action')-> // due to our used HTTP auth, the request is redirected to our secure module isForwardedTo('auth', 'login')-> // it redirects back to the original uri isRedirected(true)-> // we have to follow the redirect, otherwise we do not get // the correct response followRedirect()-> // did we recieved the correct response? with('request')->begin()-> isParameter('module', 'some_module')-> isParameter('action', 'some_action')-> end()-> responseContains('foobar'); |
Author: BleedingMoon
Where I could find the browser class?!?
Using symfony 1.2 the browser/test class is already given in the skeleton of a functional test with:
$browser = new sfTestFunctional(new sfBrowser());
I think it started with 1.2 or 1.1, where not the browser class directly was used in functional tests, but a functional test class.
Check the classes sfTestFunctional and sfTestFunctionalBase in the lib/test dir. Other methods, like the followRedirect one is passed to the sfBrowserBase (lib/util) class with the help of the magic __call method.
What I fail to see here is how you can test something *past* the authentication? You are testing that someone cannot see the secured action but how do you authenticate and test the code that’s executed after a successful authentication?
Cheers and thanks! Daniel
@annis
All this stuff tests passing the authentication correctly:
// did we recieved the correct response?
with(’request’)->begin()->
isParameter(’module’, ’some_module’)->
isParameter(’action’, ’some_action’)->
end()->
responseContains(’foobar’);
We check if the correct module is executed and if the response contains the correct content. ‘foobar’ (some dummy content of course) is only displayed for authenticated users.
Hi BleedingMoon,
I tried your code on my project but it does not pass the isRedirected(true) part. When I put a responseContains(”) after the isForwardedTo(’auth’, ‘login’) the I see my login form !?
Shouldn’t it be first submitted before checking if it is redirected ? Or am I missing something?
It’s been a while that I try to create a successful functional test but with no success :(
Hope you can help me out.
thx
@Toni
I am talking about testing HTTP Auth here. There is no standard login form at all in my application.
The process of testing a normal login via a website is completely different, therefore the test code too.