Рубрики
Uncategorized

Тестирование промежуточного программного обеспечения laravel с использованием HTTP-теста

Автор оригинала: David Wong.

Эта статья переслана из профессионального сообщества разработчиков laravel, оригинальная ссылка: https://learnku.com/laravel/t…

В этой статье я покажу вам пример использования HTTP для тестирования промежуточного программного обеспечения. Тестирование на уровне HTTP более адаптируемо к изменениям и более читабельно.

В недавней полной трансляции с Адамом Уотаном и Тейлором Отуэллом( http://www.fullstackradio.com/72 ) В программе приятно слышать, что они нашли много практических преимуществ в тестировании HTTP. Я нахожу, что HTTP-тесты легче писать и поддерживать, но мне кажется , что я тестирую неправильно ™ или не моделирую (объект), изолирую каждый тестовый элемент так же, как обман. Если вы еще не слышали этот эпизод, послушайте его. В нем полно хороших практических советов по тестированию.

вводить

Ранее в этом году я создал промежуточное программное обеспечение для проверки и защиты веб-крючка mailgun в одном из своих проектов и описал это в разделе входящая обработка электронной почты в larravel с помощью mailgun в новостях larravel. Вкратце, я продемонстрирую, как использовать промежуточное программное обеспечение laravel для проверки веб-соединения mailgun (для обеспечения веб-соединения) при обработке входящей электронной почты на самом деле Из почтового пистолета).

При настройке основной части веб-крючка mailgun подпись как часть полезной нагрузки HTTP post рекомендуется проверять с помощью подписи, метки времени и маркера, предоставленных rquest для защиты вашего веб-крючка. Это полное промежуточное программное обеспечение, которое я выпустил:

php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Response;

class ValidateMailgunWebhook
{
    public function handle($request, Closure $next)
    {
        if (!$request->isMethod('post')) {
            abort(Response::HTTP_FORBIDDEN, 'Only POST requests are allowed.');
        }

        if ($this->verify($request)) {
            return $next($request);
        }

        abort(Response::HTTP_FORBIDDEN, 'The webhook signature was invalid.');
    }

    protected function buildSignature($request)
    {
        return hash_hmac(
            'sha256',
            sprintf('%s%s', $request->input('timestamp'), $request->input('token')),
            config('services.mailgun.secret')
        );
    }

    protected function verify($request)
    {
        if (abs(time() - $request->input('timestamp')) > 15) {
            return false;
        }

        return $this->buildSignature($request) === $request->input('signature');
    }
}

Промежуточное программное обеспечение принимает только POST Запросите и сравните входящую подпись с подписью, сгенерированной с помощью ключа mailgun.

Я видел различные способы тестирования промежуточного программного обеспечения, такие как создание его непосредственно в модульных тестах, моделирование объектов по мере необходимости и прямой запуск промежуточного программного обеспечения. В этой статье я покажу вам, как протестировать это промежуточное программное обеспечение с использованием более высокого уровня HTTP-тестирования. Весь ваш стек будет запущен в тесте, Сделает вас более уверенным Ваше приложение будет работать так, как ожидалось.

Не привязывайте тест непосредственно к конкретной реализации промежуточного программного обеспечения Это важное преимущество, о котором вы можете узнать. Мы можем полностью переработать промежуточное программное обеспечение без изменения каких-либо тестов или моделирования обновлений, чтобы убедиться, что промежуточное программное обеспечение работает должным образом. Я уверен, что вы обнаружите, что эти тесты будут более надежными.

для настройки

Давайте воспользуемся примером проекта laravel 5.5 для быстрого создания теста вышеупомянутого промежуточного программного обеспечения:

$ laravel new middleware-tests

#Switch to the middleware tests folder
$ cd $_

$ php artisan make:middleware ValidateMailgunWebhook

Получите приведенный выше код промежуточного программного обеспечения и вставьте его в файл промежуточного программного обеспечения.

Затем добавьте промежуточное программное обеспечение в app/Http/Kernel.php В документе:

protected $routeMiddleware = [
    // ...
    'mailgun.webhook' => \App\Http\Middleware\ValidateMailgunWebhook::class,
];

Написание HTTP-тестов

Нам даже не нужно писать никаких тестов для этого промежуточного программного обеспечения routes/api.php Чтобы проверить это!

Во-первых, давайте создадим файл функционального теста:

$ php artisan make:test SecureMailgunWebhookTest

Проверьте промежуточное программное обеспечение mailgun. Вот что мы хотим протестировать, чтобы убедиться, что промежуточное программное обеспечение работает должным образом:

  1. Любой HTTP-глагол, отличный от POST Должно вызвать 403 Запрещено Ответ.
  2. Должна быть создана неверная подпись 403 Запрещено Ответ.
  3. Действительная подпись должна пройти и попасть на вызываемый маршрут.
  4. Старая метка времени должна вызывать 403 Запрещено Ответ.

Тестирование недопустимых методов HTTP

С помощью этого введения давайте напишем наш первый тест и настроим наш тест.

Обновление с помощью SecureMailgunWebhookTest Документ:

set('services.mailgun.secret', 'secret');

        \Route::middleware('mailgun.webhook')->any('/_test/webhook', function () {
            return 'OK';
        });
    }

    /** @test */
    public function it_forbids_non_post_methods()
    {
        $this->withoutExceptionHandling();

        $exceptionCount = 0;
        $httpVerbs = ['get', 'put', 'patch', 'delete'];

        foreach ($httpVerbs as $httpVerb) {
            try {
                $response = $this->$httpVerb('/_test/webhook');
            } catch (HttpException $e) {
                $exceptionCount++;
                $this->assertEquals(Response::HTTP_FORBIDDEN, $e->getStatusCode());
                $this->assertEquals('Only POST requests are allowed.', $e->getMessage());
            }
        }

        if (count($httpVerbs) === $exceptionCount) {
            return;
        }

        $this->fail('Expected a 403 forbidden');
    }
}

остаться Настройка() Метод, мы определяем поддельный ключ почтового пистолета, чтобы мы могли писать наши тесты против этого ключа, а затем использовать any() Метод маршрутизации определяет глобальный (охватывающий все) маршрут. Наша маршрутизация позволит нам использовать поддельный тестовый маршрут для выполнения HTTP-запросов с использованием промежуточного программного обеспечения.

Введено в laravel 5.5 без обработки исключений() Этот метод означает, что мы можем сами поймать брошенное исключение в тесте, вместо того, чтобы использовать его HTTP Ответ для отображения этого исключения.

попробуй/поймай Обеспечит, чтобы для каждого HTTP Запросить захват для HttpException , также предоставляет счетчик инкрементных исключений. Если мы зафиксируем количество исключений с помощью нашего теста HTTP Если количество запросов совпадает, тест проходит. В противном случае, если наш запрос не вызовет исключения $, будет вызван метод this->fail () .

Я предпочитаю метод перехвата и утверждения исключений использованию аннотаций. Это заставляет меня чувствовать себя яснее, и я могу утверждать исключения, чтобы убедиться, что они соответствуют моим ожиданиям.

Вы можете запустить тест функции промежуточного программного обеспечения напрямую, используя следующую команду phpunit:

# Run all tests in the file
$ ./vendor/bin/phpunit tests/Feature/SecureMailgunWebhookTest.php

# Filter a specific method
$ ./vendor/bin/phpunit \
  tests/Feature/SecureMailgunWebhookTest.php \
  --filter=it_forbids_non_post_methods

Проверка недействительной подписи

Следующий тест проверяет, не являются ли недопустимые подписи причиной 403 Запрещенной ошибки 。 Этот тест отличается от первого теста тем, что он использует POST Метод, но отправить неверные данные запроса:

/** @test */
public function it_aborts_with_an_invalid_signature()
{
    $this->withoutExceptionHandling();

    try {
        $this->post('/_test/webhook', [
            'timestamp' => abs(time() - 100),
            'token' => 'invalid-token',
            'signature' => 'invalid-signature',
        ]);
    } catch (HttpException $e) {
        $this->assertEquals(Response::HTTP_FORBIDDEN, $e->getStatusCode());
        $this->assertEquals('The webhook signature was invalid.', $e->getMessage());
        return;
    }

    $this->fail('Expected the webhook signature to be invalid.');
}

Мы передаем поддельные данные, которые приведут к недействительной подписи, а затем утверждаем, что HttpException Задается правильный статус ответа и сообщения.

Проверьте правильность подписи

Когда webhook отправляет действительную подпись, маршрут обрабатывает ответ, не прерывая промежуточное программное обеспечение. Промежуточное программное обеспечение вызывает verify() , а затем вызывается, когда подпись совпадает $next( ) :

if ($this->verify($request)) {
    return $next($request);
}

Чтобы написать этот тест, нам нужно отправить действительную подпись, метку времени и токен. Мы создадим хэш-версию SHA256 в тестовом классе, которая является почти копией того же метода в промежуточном программном обеспечении. Как промежуточное программное обеспечение, так и наши тесты будут использоваться в setup() Метод services.mailgun.secret Ключ:

/** @test */
public function it_passes_with_a_valid_signature()
{
    $this->withoutExceptionHandling();

    $timestamp = time();
    $token = 'token';
    $response = $this->post('/_test/webhook', [
        'timestamp' => $timestamp,
        'token' => $token,
        'signature' => $this->buildSignature($timestamp, $token),
    ]);

    $this->assertEquals('OK', $response->getContent());
}

protected function buildSignature($timestamp, $token)
{
    return hash_hmac(
        'sha256',
        sprintf('%s%s', $timestamp, $token),
        config('services.mailgun.secret')
    );
}

Наш тест использует тот же код для создания подписей в промежуточном программном обеспечении, поэтому мы можем генерировать действительные подписи, ожидаемые промежуточным программным обеспечением. В конце теста мы утверждаем, что содержимое ответа, возвращенного в пути теста, равно “ОК”..

Тест не удался со старой меткой времени

Еще одна мера предосторожности, которую принимает наше промежуточное программное обеспечение, – это если метка времени Если приложение старое, запрос не может быть продолжен. Тест похож на другие тесты, в которых мы утверждаем, что потерпели неудачу, но на этот раз мы делаем все допустимым (подписи и токены) за исключением Вне метки времени:

/** @test */
public function it_fails_with_an_old_timestamp()
{
    try {
        $this->withoutExceptionHandling();

        $timestamp = abs(time() - 16);
        $token = 'token';
        $response = $this->post('/_test/webhook', [
            'timestamp' => $timestamp,
            'token' => $token,
            'signature' => $this->buildSignature($timestamp, $token),
        ]);
    } catch (HttpException $e) {
        $this->assertEquals(Response::HTTP_FORBIDDEN, $e->getStatusCode());
        $this->assertEquals('The webhook signature was invalid.', $e->getMessage());
        return;
    }

    $this->fail('The timestamp should have failed verification.');
}

Пристальное внимание $метка времени(time() - 16); Это приведет к аннулированию сравнения временных меток промежуточного программного обеспечения.

Учить больше

Это быстрый рендеринг тестового промежуточного программного обеспечения на уровне HTTP. Я предпочитаю этот уровень тестирования, потому что использование насмешек над промежуточным программным обеспечением может быть утомительным и привязанным к конкретной реализации. Если я решу провести рефакторинг позже, мне, вероятно, придется переписать свои тесты в соответствии с новым промежуточным программным обеспечением. При тестировании HTTP я мог свободно рефакторировать промежуточное программное обеспечение и ожидать тех же результатов.

Написание [HTTP-теста] в laravel( https://laravel.com/docs/5.5/… ) Это очень просто, и я обнаружил, что провожу больше тестов на этом уровне. Я верю, что тесты, которые я пишу, легко понять, потому что мы ни над чем не издеваемся. Вы должны быть знакомы с утверждением (функцией) набора тестов laravel для тестирования. Эти инструменты делают ваше тестирование проще и, смею сказать, интереснее.

Если вы не знакомы с тестированием, вы также можете просмотреть тестируемый laravel в новостях laravel. Я тоже прошел через этот процесс; если вы только начинаете тестировать веб-приложение, это хороший ресурс.

Оригинал: “https://developpaper.com/testing-larravel-middleware-using-http-test/”