Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save asvae/7a80606df00df4423ef7 to your computer and use it in GitHub Desktop.
Save asvae/7a80606df00df4423ef7 to your computer and use it in GitHub Desktop.
# Тестирование cookies в Laravel и phpunit
Бегло пробежавшись глазами по мануалу, может показаться, что вопрос это простой. Но давайте посмотрим на простейший случай.
## Условие
Пользователь вбивает в браузере `register/123` и переходит на страницу. Его редиректит на `register`, выдавая параллельно кукез `referral: 123`. Пользователь регистрируется — реферал должен закрепиться в базе. Нужно протестировать юзкеис.
## Решение 1 (?)
Казалось бы, все просто:
```
$this->visit('register/123')->seeCookie('referral');
```
Вот только тест красный. Разберемся:
Заглянув в код, наблюдаем, что `visit()` вызывает `$this->followRedirects()`. А ларавель не передает кукезы при редиректе.
Почему бы не разбить тест на два.
## Решение 2 (?)
#### Тест 1
```
$this->get('register/123');
$this->seeCookie('referral');
```
C первым тестом все хорошо. Он зеленый, как огурчик. Дальше мы его трогать не будем.
#### Тест 2
```
$this->call('post', 'register', $this->userData, ['referral' => '123']);
$this-assertTrue($this->checkUserHasReferral('123')); // Проверить, сохранилось ли значение в базе.
```
А вот второй — снова неумолимо краснеет. Мало того, `dd($request->cookies)` в контроллере сообщает, что никаких кукезов не было и вообще вы адресом ошиблись.
Проблема здесь в том, что ларавель куки еще и шифрует по-умолчанию. Что приводит нас к финальному решению:
## Решение 3 (!)
#### Тест 2
```
$this->app->resolving(App\Http\Middleware\EncryptCookies::class,
function ($object) {
$object->disableFor('referral');
});
$cookie = ['referral' => '123'];
$this->call('post', 'register', $this->userData, ['referral' => '123']);
$this-assertTrue($this->checkUserHasReferral('123'));
```
Что здесь происходит? В тот момент, когда ларавель попытается вызвать инстант класса `EnctyptCookies`, отвечающего за шифрование кукезов, триггерится [вышеописанное замыкание](https://laravel.com/docs/5.2/container#container-events), которое модифицирует объект так, чтобы он игнорировал куки с определенным значением.
Функционал по снятию шифрования с определенных кукезов легко можно выделить в родительский тест-кейс:
```
/**
* @param array|string $cookies
* @return $this
*/
protected function disableCookiesEncryption($cookies)
{
$this->app->resolving(EncryptCookies::class,
function ($object) use ($cookies) {
$object->disableFor($cookies);
});
return $this;
}
```
А в конкретном тест-кейсе, уже запустить в методе `setUp()`:
```
public function setUp()
{
parent::setUp();
$this->disableCookiesEncryption(Referral::COOKIE_NAME);
}
```
Альтернативным вариантом будет, наоборот, шифровать куки перед тем, как положить в запрос:
```
$cookie = [ 'referral' => \Crypt::encrypt('123') ];
```
# Заключение
И вот, тесты позеленели, а вы научились автоматически проверять кукезы без лишней головной боли.
@asvae
Copy link
Author

asvae commented Jan 26, 2016

Тестирование cookies в Laravel и phpunit

Бегло пробежавшись глазами по мануалу, может показаться, что вопрос это простой. Но давайте посмотрим на простейший случай.

Условие

Пользователь вбивает в браузере register/123 и переходит на страницу. Его редиректит на register, выдавая параллельно кукез referral: 123. Пользователь регистрируется — реферал должен закрепиться в базе. Нужно протестировать юзкеис.

Решение 1 (?)

Казалось бы, все просто:

$this->visit('register/123')->seeCookie('referral');

Вот только тест красный. Разберемся:

Заглянув в код, наблюдаем, что visit() вызывает $this->followRedirects(). А ларавель не передает кукезы при редиректе.
Почему бы не разбить тест на два.

Решение 2 (?)

Тест 1

$this->get('register/123');
$this->seeCookie('referral');

C первым тестом все хорошо. Он зеленый, как огурчик. Дальше мы его трогать не будем.

Тест 2

$this->call('post', 'register', $this->userData, ['referral' => '123']);
$this-assertTrue($this->checkUserHasReferral('123')); // Проверить, сохранилось ли значение в базе.

А вот второй — снова неумолимо краснеет. Мало того, dd($request->cookies) в контроллере сообщает, что никаких кукезов не было и вообще вы адресом ошиблись.

Проблема здесь в том, что ларавель куки еще и шифрует по-умолчанию. Что приводит нас к финальному решению:

Решение 3 (!)

Тест 2

$this->app->resolving(App\Http\Middleware\EncryptCookies::class,
    function ($object) {
        $object->disableFor('referral');
    });
$cookie = ['referral' => '123'];
$this->call('post', 'register', $this->userData, ['referral' => '123']);
$this-assertTrue($this->checkUserHasReferral('123'));

Что здесь происходит? В тот момент, когда ларавель попытается вызвать инстант класса EnctyptCookies, отвечающего за шифрование кукезов, триггерится вышеописанное замыкание, которое модифицирует объект так, чтобы он игнорировал куки с определенным значением.

Функционал по снятию шифрования с определенных кукезов легко можно выделить в родительский тест-кейс:

/**
 * @param array|string $cookies
 * @return $this
 */
protected function disableCookiesEncryption($cookies)
{
    $this->app->resolving(EncryptCookies::class,
        function ($object) use ($cookies) {
            $object->disableFor($cookies);
        });

    return $this;
}

А в конкретном тест-кейсе, уже запустить в методе setUp():

public function setUp()
{
    parent::setUp();
    $this->disableCookiesEncryption(Referral::COOKIE_NAME);
}

Альтернативным вариантом будет, наоборот, шифровать куки перед тем, как положить в запрос:

$cookie = [ 'referral' => \Crypt::encrypt('123') ];

Заключение

И вот, тесты позеленели, а вы научились автоматически проверять кукезы без лишней головной боли.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment