Рубрики
Uncategorized

Использование признаков для организации тестов PHPUnit

Как я организовывал тестовые занятия. С пометкой phpunit, тестирование, php.

Я хотел бы поделиться тем, как я организовывал тесты в PHPUnit. Может быть, вы уже пробовали это раньше, и, может быть, это ужасная идея. То, что сработало для меня, может не сработать для вас.

Я предполагаю, что вы уже писали тесты раньше и немного знаете PHP. Давайте запрыгнем внутрь!

Пример настройки

Давайте начнем с тестирования платформы для ведения блогов, такой как Dev. Он имеет API и веб-интерфейс и отправляет электронные письма подписчикам автора при публикации новой статьи.

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

public function test_no_emails_sent_for_author_with_no_followers(): void
{
    $this->givenApiAuthenticatedAsUser('1');
    $this->api->post('/articles', ['content' => '...', 'published' => true]);
    $this->emails->assertCountEmails(0);
}

Здесь не хватает нескольких вещей.

  • Где $this->данный Api Аутентифицирован Как Пользователь определен?
  • Как $this->api настройка?
  • Как насчет $this->электронные письма ?

Давайте сначала посмотрим на $this->api . Это может быть любой клиент API, например Guzzle или HttpClient Symfony. Не важно, какой из них здесь, но он будет определен примерно так

public function setUp(): void
{
    $this->api = new SomeClient('https://api.blog.example.com', ...);
}

Далее $this->данный Api Аутентифицирован Как Пользователь . Для наших целей это имитирует токен OAuth и добавляет его в качестве заголовка следующим образом

protected function givenApiAuthenticatedAsUser(string $userId): void
{
    $token = 'test token';
    $this->api->headers['Authorization'] = "Bearer $token";
}

Наконец, $это->электронные письма . Давайте предположим, что это библиотека утверждений, которую вы нашли для Mailhog (хотя я не уверен, что она действительно существует).

public function setUp(): void
{
    $this->emails = new SomeMailhogAssertionClient('http://mailhog.test');
    $this->emails->reset();
}

Организация с чертами характера

Я уверен, что вы можете представить себе несколько тестов в этой вымышленной установке, например Статьи ApiTest , Тест Api пользователей и Пользовательский веб-тест . Последний может использовать BrowserKit или Panther но я пропущу здесь подробности, так как это то же самое, что и настройка API.

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

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

Поскольку в PHPUnit у нас нет каких-либо опций внедрения зависимостей, которые бы охватывали это, и доступ к некоторым из наших методов осуществляется напрямую через $this , мы сделаем это с помощью Черт и Аннотации PHPUnit .

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

class ArticlesApiTest
{
    use ApiTestTrait;
    use EmailsTestTrait;

    public function test_no_emails_sent_for_author_with_no_followers(): void
    {
        $this->givenApiAuthenticatedAsUser('1');
        $this->api->post('/articles', ['content' => '...', 'published' => true]);
        $this->emails->assertCountEmails(0);
    }
}

trait ApiTestTrait
{
    /**
     * @before
     **/
    public function setUpApiBeforeTest(): void
    {
        $this->api = new SomeClient('https://api.blog.example.com', ...);
    }

    protected function givenApiAuthenticatedAsUser(string $userId): void
    {
        $token = 'test token';
        $this->api->headers['Authorization'] = "Bearer $token";
    }
}

trait EmailsTestTrait
{
    /**
     * @before
     **/
    public function setUpEmailsBeforeTest(): void
    {
        $this->emails = new SomeMailhogAssertionClient('http://mailhog.test');
        $this->emails->reset();
     }
}

Путем замены настройте с помощью методов с уникальными именами и @перед аннотацией мы можем разделить код на отдельные фрагменты, на которые мы можем подписаться.

Теперь сброс электронной почты, который вызывает медленный вызов API, происходит только тогда, когда мы явно включаем его в наш тест. Наш список автозаполнения IDE более чистый, потому что он знает, когда мы можем использовать или не использовать определенные функции или утверждения.

Мы также можем расширить другой класс, если потребуется, например WebTestCase (Если кто-либо из участников Symfony читает, я думаю, было бы здорово, если бы мы могли вместо этого использовать WebTestCase ).

Дополнительные примеры черт

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

Издевательское глобальное состояние, как время?

trait MockedClockTestTrait
{
    protected function givenTimeIs(\DateTimeImmutable $time): void
    {
        // Populate a mocked time object, 
        // or use Clock Mocking from PHPUnit Bridge
    }
}

У вас много утверждений о JSON?

trait JsonAssertionsTrait
{
    public function assertJsonContainsKey(): void;
    public function assertJsonHasValueAtPath(string $jsonPath, $expectedValue): void;
}

Сбросьте базу данных в некоторых тестах и сохраняйте объекты с помощью JSON

trait DatabaseTestTrait
{
    /**
     * @var \Doctrine\Common\Persistence\ObjectManager
     */
    protected $objectManager;

    abstract protected static function getContainer(): ContainerInterface;

    /**
     * @before
     */
    public function resetDatabaseBeforeTest(): void
    {
        $registry = static::getContainer()->get('doctrine');
        $connection = $registry->getConnection();

        $this->objectManager = $registry->getManager();

        $connection->executeUpdate('DELETE FROM articles');
        $connection->executeUpdate('DELETE FROM users');
    }
}

Как ты думаешь? Использовали ли вы этот метод раньше? Какие-нибудь недостатки?

Что бы вы добавили в черту характера?

Оригинал: “https://dev.to/adamquaile/using-traits-to-organise-phpunit-tests-39g3”