Тестирование ajax

Всё про тестирование в Yii 2.0
Ответить
kwasti
Сообщения: 262
Зарегистрирован: 2016.01.28, 16:14

Тестирование ajax

Сообщение kwasti »

Пробую применять тестирование в своем проекте.
Столкнулся со следующим:
1. Если задать локализацию, то перестает проходить базовый тест (даже если исправляю текст на обработку через t() ). В итоге вопрос как проверять корректность локализации? (если требуется проверка еще и корректности отображения view в зависимости от языка)
2. как выполнять функциональный тест, если контроллер обрабатывает ajax запросы?
3. как при этом(п.2) передавать параметры ajax запроса контроллеру?

и наверно совсем "нубский" вопрос:
4. Как тестировать вот такой класс?
на примере AuthHandler (регистрация через сторонние серверы)
вот часть его кода

Код: Выделить всё

class AuthHandler
{
    /**
     * @var ClientInterface
     */
    private $client;
    public $email;
    public $nickname;
    public $full_name;
    public $photo;
    public $sex;
    public function __construct(ClientInterface $client)
    {
        $this->client = $client;
    }

    /**
     * @param $attributes
     */
    protected function yandex($attributes){
        $this->email = ArrayHelper::getValue($attributes, 'default_email');
        $this->nickname = ArrayHelper::getValue($attributes, 'login');
        $this->full_name = ArrayHelper::getValue($attributes,'real_name','');
        if (!ArrayHelper::getValue($attributes,'is_avatar_empty',true)){
            $this->photo ='https://avatars.yandex.net/get-yapic/'.ArrayHelper::getValue($attributes,'default_avatar_id').'/islands-200';
        }
        $this->sex = ArrayHelper::getValue($attributes,'sex','');
    }
    /**
     * @param $attributes
     */
    protected function google($attributes){
        $this->email = ArrayHelper::getValue($attributes, 'email');
        $this->nickname =ArrayHelper::getValue($attributes,'name');
        $this->full_name = ArrayHelper::getValue($attributes,'given_name','');
        $this->sex='';
        $this->photo = ArrayHelper::getValue($attributes, 'picture');
    }
        public function handle()
    {
        $attributes = $this->client->getUserAttributes();
        Yii::error($attributes);
        switch ($this->client->getId()){
            case 'yandex':
                $this->yandex($attributes);
                break;
            case 'google':
                $this->google($attributes);
                break;
            default:
                $this->other($attributes);
        }
        $id = ArrayHelper::getValue($attributes, 'id');
        /* @var Auth $auth */
        $auth = Auth::find()->where([
            'source' => $this->client->getId(),
            'source_id' => $id,
        ])->one();

        if (Yii::$app->user->isGuest) {
            if ($auth) { // login
                /* @var User $user */
                $user = $auth->user;
                $this->updateUserInfo($user);
                Yii::$app->user->login($user, Yii::$app->params['user.rememberMeDuration']);
                $this->saveProfile($user);
            } else { // signup
                if ($this->email !== null && User::find()->where(['email' => $this->email])->exists()) {
                    Yii::$app->getSession()->setFlash('error', [
                        Yii::t('app', "User with the same email as in {client} account already exists but isn't linked to it. Login using email first to link it.", ['client' => $this->client->getTitle()]),
                    ]);
                } else {
                    $password = Yii::$app->security->generateRandomString(6);
                    $user = new User([
                        'username' => $this->nickname,
                        'github' => $this->nickname,
                        'email' => $this->email,
                        'password' => $password,
                    ]);
                    $user->generateAuthKey();
                    $user->generatePasswordResetToken();
                    $user->status=User::STATUS_ACTIVE;
                    $transaction = User::getDb()->beginTransaction();

                    if ($user->save()) {
                        $auth = new Auth([
                            'user_id' => $user->id,
                            'source' => $this->client->getId(),
                            'source_id' => (string)$id,
                        ]);
                        if ($auth->save()) {
                            if ($this->saveProfile($user)){
                                $transaction->commit();
                                Yii::$app->user->login($user, Yii::$app->params['user.rememberMeDuration']);
                                Yii::error($user);
                                //Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0)
                            } else {
                                $transaction->rollBack();
                                Yii::$app->getSession()->setFlash('error', [
                                    Yii::t('app', 'Unable to save profile: {errors}', [
                                        'client' => $this->client->getTitle(),
                                        'errors' => json_encode($auth->getErrors()),
                                    ]),
                                ]);
                            }
                        } else {
                            $transaction->rollBack();
                            Yii::$app->getSession()->setFlash('error', [
                                Yii::t('app', 'Unable to save {client} account: {errors}', [
                                    'client' => $this->client->getTitle(),
                                    'errors' => json_encode($auth->getErrors()),
                                ]),
                            ]);
                        }
                    } else {
                        $transaction->rollBack();
                        Yii::$app->getSession()->setFlash('error', [
                            Yii::t('app', 'Unable to save user: {errors}', [
                                'client' => $this->client->getTitle(),
                                'errors' => json_encode($user->getErrors()),
                            ]),
                        ]);
                    }
                }
            }
        } else { // user already logged in
            if (!$auth) { // add auth provider
                $auth = new Auth([
                    'user_id' => Yii::$app->user->id,
                    'source' => $this->client->getId(),
                    'source_id' => (string)$attributes['id'],
                ]);
                $transaction = User::getDb()->beginTransaction();
                if ($auth->save()) {
                    /** @var User $user */
                    $user = $auth->user;
                    $this->updateUserInfo($user);
                    if ($this->saveProfile($user)){
                        $transaction->commit();
                        Yii::$app->user->login($user, Yii::$app->params['user.rememberMeDuration']);
                        Yii::$app->getSession()->setFlash('success', [
                            Yii::t('app', 'Linked {client} account.', [
                                'client' => $this->client->getTitle()
                            ]),
                        ]);
//                        Yii::error($user);
                        //Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0)
                    } else {
                        $transaction->rollBack();
                        Yii::$app->getSession()->setFlash('error', [
                            Yii::t('app', 'Unable to save profile: {errors}', [
                                'client' => $this->client->getTitle(),
                                'errors' => json_encode($auth->getErrors()),
                            ]),
                        ]);
                    }

                } else {
                    $transaction->rollBack();
                    Yii::$app->getSession()->setFlash('error', [
                        Yii::t('app', 'Unable to link {client} account: {errors}', [
                            'client' => $this->client->getTitle(),
                            'errors' => json_encode($auth->getErrors()),
                        ]),
                    ]);
                }
            } else { // there's existing auth
                Yii::$app->getSession()->setFlash('error', [
                    Yii::t('app',
                        'Unable to link {client} account. There is another user using it.',
                        ['client' => $this->client->getTitle()]),
                ]);
            }
        }
    }
как в этом случае написать тест?
часть методов protected, а тот что public затрагивает несколько вещей, к которым я не знаю как подойти.
как правильно задать client, от типа которого будет вызываться разный обработчик.

научите на этом примере как правильно будет выглядеть тест клиента от яндекса? (Офиц. документации кроме простых примеров - подобногоне хватает: тут и отношения между таблицами, и интерфейсы, транзакции и отлов обработки ошибок записи и интернационализация и запись алерта)
Аватара пользователя
ElisDN
Сообщения: 5841
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Тестирование ajax

Сообщение ElisDN »

kwasti писал(а): 2020.07.09, 14:47 1. Если задать локализацию, то перестает проходить базовый тест (даже если исправляю текст на обработку через t() ). В итоге вопрос как проверять корректность локализации? (если требуется проверка еще и корректности отображения view в зависимости от языка)
Если язык задаётся в адресе, то в тесте переходить по адресам с языком. Если же в заголовке Accept-Lang, то и проставляйте этот заголовок через $I->haveHttpHeader('Accept-Lang', 'ru')
kwasti писал(а): 2020.07.09, 14:47 2. как выполнять функциональный тест, если контроллер обрабатывает ajax запросы?
3. как при этом передавать параметры ajax запроса контроллеру?
Через $I->sendAjaxGetRequest(...) и $i->sendAjaxPostRequest(...).

А так вообще Ajax-запрос в Yii отличается от обычного наличием заголовка "X-Requested-With: XMLHttpRequest".
kwasti писал(а): 2020.07.09, 14:47 4. часть методов protected, а тот что public затрагивает несколько вещей, к которым я не знаю как подойти.
как правильно задать client, от типа которого будет вызываться разный обработчик. Научите на этом примере как правильно будет выглядеть тест клиента от яндекса?
Через создание стаба клиента через createStub и подмену его методов:

Код: Выделить всё

$client = $this->createStub(Client::class);
$request->method('getId')->willReturn('yandex');
kwasti писал(а): 2020.07.09, 14:47 Как тестировать вот такой класс? Как в этом случае написать тест?
тут и отношения между таблицами, и интерфейсы, транзакции и отлов обработки ошибок записи и интернационализация и запись алерта)
Для такой мешанины сочинять тест очень сложно.

Тесты удобно делать для чётко разделённых объектов, которые никуда не ходят напрямую через Yii::$app.

Как пример можете посмотреть тесты для выбора мобильной темы сайта
Или как клиент и обработчик ошибок выносятся в отдельные классы на примере рефакторинга геолокатора.
kwasti
Сообщения: 262
Зарегистрирован: 2016.01.28, 16:14

Re: Тестирование ajax

Сообщение kwasti »

Дмитрий!
Спасибо за развернутый ответ!
Ответить