|  | 
| 4 | 4 | How to Simulate HTTP Authentication in a Functional Test | 
| 5 | 5 | ======================================================== | 
| 6 | 6 | 
 | 
| 7 |  | -If your application needs HTTP authentication, pass the username and password | 
| 8 |  | -as server variables to ``createClient()``:: | 
|  | 7 | +Authenticating requests in functional tests can slow down the entire test suite. | 
|  | 8 | +This could become an issue especially when the tests reproduce the same steps | 
|  | 9 | +that users follow to authenticate, such as submitting a login form or using | 
|  | 10 | +OAuth authentication services. | 
| 9 | 11 | 
 | 
| 10 |  | -    $client = static::createClient(array(), array( | 
| 11 |  | -        'PHP_AUTH_USER' => 'username', | 
| 12 |  | -        'PHP_AUTH_PW'   => 'pa$$word', | 
| 13 |  | -    )); | 
|  | 12 | +This article explains the two most popular techniques to avoid these issues and | 
|  | 13 | +create fast tests when using authentication. | 
| 14 | 14 | 
 | 
| 15 |  | -You can also override it on a per request basis:: | 
|  | 15 | +Using a Faster Authentication Mechanism Only for Tests | 
|  | 16 | +------------------------------------------------------ | 
| 16 | 17 | 
 | 
| 17 |  | -    $client->request('DELETE', '/post/12', array(), array(), array( | 
| 18 |  | -        'PHP_AUTH_USER' => 'username', | 
| 19 |  | -        'PHP_AUTH_PW'   => 'pa$$word', | 
| 20 |  | -    )); | 
|  | 18 | +When your application is using a ``form_login`` authentication, you can make | 
|  | 19 | +your tests faster by allowing them to use HTTP authentication. This way your | 
|  | 20 | +tests authenticate with the simple and fast HTTP Basic method whilst your real | 
|  | 21 | +users still log in via the normal login form. | 
| 21 | 22 | 
 | 
| 22 |  | -When your application is using a ``form_login``, you can simplify your tests | 
| 23 |  | -by allowing your test configuration to make use of HTTP authentication. This | 
| 24 |  | -way you can use the above to authenticate in tests, but still have your users | 
| 25 |  | -log in via the normal ``form_login``. The trick is to include the ``http_basic`` | 
| 26 |  | -key in your firewall, along with the ``form_login`` key: | 
|  | 23 | +The trick is to use the ``http_basic`` authentication in your application | 
|  | 24 | +firewall, but only in the configuration file used by tests: | 
| 27 | 25 | 
 | 
| 28 | 26 | .. configuration-block:: | 
| 29 | 27 | 
 | 
| @@ -54,3 +52,72 @@ key in your firewall, along with the ``form_login`` key: | 
| 54 | 52 |                 ), | 
| 55 | 53 |             ), | 
| 56 | 54 |         )); | 
|  | 55 | +
 | 
|  | 56 | +Tests can now authenticate via HTTP passing the username and password as server | 
|  | 57 | +variables using the second argument of ``createClient()``:: | 
|  | 58 | + | 
|  | 59 | +    $client = static::createClient(array(), array( | 
|  | 60 | +        'PHP_AUTH_USER' => 'username', | 
|  | 61 | +        'PHP_AUTH_PW'   => 'pa$$word', | 
|  | 62 | +    )); | 
|  | 63 | + | 
|  | 64 | +The username and password can also be passed on a per request basis:: | 
|  | 65 | + | 
|  | 66 | +    $client->request('DELETE', '/post/12', array(), array(), array( | 
|  | 67 | +        'PHP_AUTH_USER' => 'username', | 
|  | 68 | +        'PHP_AUTH_PW'   => 'pa$$word', | 
|  | 69 | +    )); | 
|  | 70 | + | 
|  | 71 | +Creating the Authentication Token | 
|  | 72 | +--------------------------------- | 
|  | 73 | + | 
|  | 74 | +If your application uses a more advanced authentication mechanism, you can't | 
|  | 75 | +use the previous trick, but it's still possible to make tests faster. The trick | 
|  | 76 | +now is to bypass the authentication process, create the *authentication token* | 
|  | 77 | +yourself and store it in the session. | 
|  | 78 | + | 
|  | 79 | +This technique requires some knowledge of the Security component internals, | 
|  | 80 | +but the following example shows a complete example that you can adapt to your | 
|  | 81 | +needs:: | 
|  | 82 | + | 
|  | 83 | +    // src/AppBundle/Tests/Controller/DefaultControllerTest.php | 
|  | 84 | +    namespace Appbundle\Tests\Controller; | 
|  | 85 | + | 
|  | 86 | +    use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; | 
|  | 87 | +    use Symfony\Component\BrowserKit\Cookie; | 
|  | 88 | +    use Symfony\Component\HttpFoundation\Response; | 
|  | 89 | +    use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; | 
|  | 90 | + | 
|  | 91 | +    class DefaultControllerTest extends WebTestCase | 
|  | 92 | +    { | 
|  | 93 | +        private $client = null; | 
|  | 94 | + | 
|  | 95 | +        public function setUp() | 
|  | 96 | +        { | 
|  | 97 | +            $this->client = static::createClient(); | 
|  | 98 | +        } | 
|  | 99 | + | 
|  | 100 | +        public function testSecuredHello() | 
|  | 101 | +        { | 
|  | 102 | +            $this->logIn(); | 
|  | 103 | +            $crawler = $this->client->request('GET', '/admin'); | 
|  | 104 | + | 
|  | 105 | +            $this->assertSame(Response::HTTP_OK, $this->client->getResponse()->getStatusCode()); | 
|  | 106 | +            $this->assertSame('Admin Dashboard', $crawler->filter('h1')->text()); | 
|  | 107 | +        } | 
|  | 108 | + | 
|  | 109 | +        private function logIn() | 
|  | 110 | +        { | 
|  | 111 | +            $session = $this->client->getContainer()->get('session'); | 
|  | 112 | + | 
|  | 113 | +            // the firewall context defaults to the firewall name | 
|  | 114 | +            $firewallContext = 'secured_area'; | 
|  | 115 | + | 
|  | 116 | +            $token = new UsernamePasswordToken('admin', null, $firewallContext, array('ROLE_ADMIN')); | 
|  | 117 | +            $session->set('_security_'.$firewallContext, serialize($token)); | 
|  | 118 | +            $session->save(); | 
|  | 119 | + | 
|  | 120 | +            $cookie = new Cookie($session->getName(), $session->getId()); | 
|  | 121 | +            $this->client->getCookieJar()->set($cookie); | 
|  | 122 | +        } | 
|  | 123 | +    } | 
0 commit comments