Функциональное тестирование Rest Full API на Codeception в Yii2

04.02.2017

При создании functional тестов для rest full api в yii2 можно столкнуться с тем же что и я, а именно особенной, рабочей настройке codeception. И так, как всегда меньше слов, больше кода. 

structure yii2 with api app

Как видим у меня есть api приложение для которого я и делаю функциональное тестирование. К слову: метод авторизации я выбрал Bearer и возврат данных в формате JSON.

Как выглядит Bearer авторизация в контроллере:

class TestController extends Controller
{
    /**
     * @inheritdoc
     */
    public function behaviors(): array
    {
        return array_merge(parent::behaviors(), [
            'authenticator' => [
                'class' => HttpBearerAuth::className(),
            ],
            'access' => [
                'class' => AccessControl::className(),
                'rules' => [
                    [
                        'allow' => true,
                        'roles' => [User::ROLE_API],
                    ],
                ],
            ],
            'verbFilter' => [
                'class' => VerbFilter::className(),
                'actions' => [
                    '*' => ['post'],
                ],
            ]
        ]);
    }

...
...

 

Доступ получают только пользователи отправившие вместе с запросом к api заголовок:

header('Authorization: Bearer DH4k972hdtz27yf8dEifsd8Z0isOsdS3xV');// длиннющая строка, это ваш токен

Инициализируем codeception в нашем приложении (api):

cd api
codecept bootstrap

Первой командой переходим в каталог приложения api. Второй создаем codeception.yml файл и дирректорию test.

Видим примерно такую картину:

codeception tests directory

Переименуем файл functional.suite.yml в api.suite.yml, так как у нас тестирование api, по сути мы этим действием придаем только смысловую нагрузку (переименуем так же папку functional в api, в _support удаляем все что связано с functional).  Вносим следующие изменения в api.suite.xml:

class_name: ApiTester
modules:
    enabled:
        - \api\tests\Helper\Api
        - Filesystem
        - \api\tests\Helper\Yii2Api
        - REST
    config:
        REST:
            depends: \api\tests\Helper\Yii2Api
            part: Json
error_level: 'E_ALL'

Важная часть данной статьи! Ключевая особенность в том, что мы подключаем собственный модуль Yii2Api, причем конфигурируем его при помощи стандартных конфигов yii2. Поэтому в папке _support/Helper создаем класс Yii2Api с содержимым:

<?php

namespace api\tests\Helper;

use Yii;
use Codeception\Module\Yii2;
use Codeception\Lib\Connector\Yii2 as Yii2Connector;
use Codeception\TestInterface;
use yii\db\Transaction;

/**
 * Class        Yii2Api
 * @package     api\tests\Helper
 * @author      Matthew P.
 * @version     1.0
 *
 * @property Yii2Connector $client
 * @property Transaction $transaction
 */
class Yii2Api extends Yii2
{
    /**
     * @param TestInterface $test
     */
    public function _before(TestInterface $test)
    {
        parent::_before($test);

        $config = isset(Yii::$app->params['api_config']) ? Yii::$app->params['api_config'] : [];

        $this->config = array_merge($this->config, $config);

        $this->client->defaultServerVars = [
            'SCRIPT_FILENAME'   => $this->client->getServerParameter('SCRIPT_FILENAME'),
            'SCRIPT_NAME'       => $this->client->getServerParameter('SCRIPT_NAME'),
            'SERVER_NAME'       => $this->client->getServerParameter('SERVER_NAME'),
            'SERVER_PORT'       => $this->client->getServerParameter('SERVER_PORT'),
        ];

        if (isset($this->config['host'])) {
            $this->client->defaultServerVars['HTTP_HOST'] = $this->config['host'];
        }

        if (parse_url($this->config['entryUrl'], PHP_URL_SCHEME) === 'https') {
            $this->client->defaultServerVars['HTTPS'] = true;
        }

        $this->client->restoreServerVars();

        if (!$this->config['cleanup'] && $this->app->has('db') && $this->app->db instanceof \yii\db\Connection && !empty($this->transaction)) {
            $this->transaction->commit();
        }
    }
}

Теперь для чего он нужен и почему на нем сконцентрированно внимание. Дело в том, что codeception при запуске, не знает входную точку в ваше приложение, попросту url через который посылать запросы. Большинство его указвают прямо в конфиге codeception примерно так:

class_name: ApiTester
modules:
    enabled:
        - \api\tests\Helper\Api
        - Filesystem
       -  Yii2
        - REST
    config:
        REST:
            url: 'http://example.loc/api'
error_level: 'E_ALL'

Или вот так:

 - Yii2:
            part: [orm, fixtures] # allow to use AR methods
            cleanup: false
            entryScript: index-test.php

Еще вариант:

- REST:
        depends: Yii2

В любом случае конфиг codeception в котором мы так уседно пытаемся указать точку входа лежит в git и теперь нужно договариваться с коллегами, чтобы у всех она была одинаковая, или вы будете каждый раз при запуске тестов править ее на свою, а потом обратно)

Как можно заметить, класс Yii2Api наследуется от Yii2 модуля, поведение то же, за исключением того, что теперь настройку точки входа, хоста и т.п. мы производим взяв их из Yii::$app->params. А это значит, что мы можем задавать настройки входной точки независимо от коллег. В принципе что тут объяснять, я надеюсь преимущество params-local.php знаете и без меня:)

Что осталось? Открываем codeception.yml и вносим изменения:

namespace: api\tests
actor: Tester
paths:
    tests: tests
    log: tests/_output
    data: tests/_data
    helpers: tests/_support
    envs: tests/_envs
settings:
    bootstrap: _bootstrap.php
    colors: true
    memory_limit: 1024M
modules:
    config:
        Yii2:
            configFile: 'config/test-local.php'
        \api\tests\Helper\Yii2Api:
            configFile: 'config/test-local.php'

 

Теперь нам нужно применить изменения и сгенерировать необходдимые файлы, выполним комманду:

codecept build

Структура после всех манипуляций выглядит так:

codeception api structure

Теперь идем в файл common\config\params-local.php и добавляем следующий код:

return [
    'adminEmail'    => 'admin@example.com',
    'supportEmail'  => 'support@example.com',
    'user.passwordResetTokenExpire' => 3600,

    /**
     * Api config
     */
    'api_config' => [
        'cleanup'     => true,
        'entryScript' => '',
        'entryUrl'    => 'http://api.example.loc/index.php',
        'host'        => 'api.example.loc'
    ],

...
...

Соответственно изменяем entryUrl и host на свои.

Все, проверяем (команду выполяем находясь в папке api, тогда запустятся только тесты для этого приложения):

codecept run

 

Что ПРИМЕРНО можно увидеть, если все прошло как по маслу:

Codeception PHP Testing Framework v2.2.9
Powered by PHPUnit 5.7.9 by Sebastian Bergmann and contributors.

Acceptance Tests (0) -----------------------------------------------------------------------------------------------------------------------------------------------------------------

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Api Tests (0) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Unit Tests (0) -----------------------------------------------------------------------------------------------------------------------------------------------------------------------

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------



Time: 3.95 seconds, Memory: 10.00MB

No tests executed!

 

 

comments powered by HyperComments