|
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,71 @@ 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\Security\Core\Authentication\Token\UsernamePasswordToken; |
| 89 | + |
| 90 | + class DefaultControllerTest extends WebTestCase |
| 91 | + { |
| 92 | + private $client = null; |
| 93 | + |
| 94 | + public function setUp() |
| 95 | + { |
| 96 | + $this->client = static::createClient(); |
| 97 | + } |
| 98 | + |
| 99 | + public function testSecuredHello() |
| 100 | + { |
| 101 | + $this->logIn(); |
| 102 | + $crawler = $this->client->request('GET', '/admin'); |
| 103 | + |
| 104 | + $this->assertTrue($this->client->getResponse()->isSuccessful()); |
| 105 | + $this->assertSame('Admin Dashboard', $crawler->filter('h1')->text()); |
| 106 | + } |
| 107 | + |
| 108 | + private function logIn() |
| 109 | + { |
| 110 | + $session = $this->client->getContainer()->get('session'); |
| 111 | + |
| 112 | + // the firewall context defaults to the firewall name |
| 113 | + $firewallContext = 'secured_area'; |
| 114 | + |
| 115 | + $token = new UsernamePasswordToken('admin', null, $firewallContext, array('ROLE_ADMIN')); |
| 116 | + $session->set('_security_'.$firewallContext, serialize($token)); |
| 117 | + $session->save(); |
| 118 | + |
| 119 | + $cookie = new Cookie($session->getName(), $session->getId()); |
| 120 | + $this->client->getCookieJar()->set($cookie); |
| 121 | + } |
| 122 | + } |
0 commit comments