Рубрики
Uncategorized

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

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

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

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

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

вводить

Ранее в этом году я создал промежуточное программное обеспечение для проверки и защиты веб-приложения mailgun в одном из своих проектов, которое описано в разделе входящая обработка электронной почты mailgun в laravel в новостях laravel. Вкратце, я покажу вам, как использовать промежуточное программное обеспечение laravel для проверки веб-крючка mailgun (чтобы убедиться, что веб-крючок На самом деле Из 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');
    }
}

оставайтесь setUp() Метод, мы определяем поддельный ключ mailgun, чтобы мы могли написать ваши тесты против этого ключа, а затем использовать любой() Метод маршрутизации определяет весь маршрут. Наша маршрутизация позволит нам использовать поддельный тестовый путь для выдачи 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 отправляет действительную подпись, маршрут обрабатывает ответ, не прерывая промежуточное программное обеспечение. Промежуточное программное обеспечение вызывает проверку() , а затем вызывается, когда подпись совпадает $next() :

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

Чтобы написать этот тест, нам нужно отправить действительную подпись, метку времени и токен. Мы создадим версию хэша SHA-256 в тестовом классе, которая является почти копией того же метода в промежуточном программном обеспечении. Промежуточное программное обеспечение и наши тесты будут использоваться в 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. Я также испытал этот процесс; если вы только начинаете тестировать веб-приложения, это хороший ресурс.