Верх страницы
Обложка к записи Как тестировать Hard Dependencies в PHPUnit с помощью Mockery
Время для прочтения: 3 мин. 7 сек.

Как тестировать Hard Dependencies в PHPUnit с помощью Mockery

Если у вас возникают вопросы: Что такое Hard Dependencies и почему это плохо? Вы можете прочитать в статье «Dependency Injection the best design pattern«.

Внедрения зависимостей (Dependency Injection) один из основных принципов, которых нужно придерживаться для написание качественного кода.

Но иногда мы сталкиваемся с проблемами, когда избежать зависимостей невозможно или же это занимает слишком много времени.

Сложность заключается в том, что зависимости мы не должны тестировать, мы должны создать для них заглушки.

Установка Mockery

Нам понадобиться библиотеку Mockery:

composer require mockery/mockery --dev

Фикстуры для Mockery

Что такое фикстуры можно прочитать в статье «Модульное тестирование (Unit tests) с помощью PHPUnit«.

Для работы библиотеки Mockery нам нужно изменить фикстуры:

use PHPUnit\Framework\TestCase;

class Test_Bird extends TestCase {

	 /**
	 * Setup test
	 */
	public function setUp(): void {
		Mockery::resetContainer();
		parent::setUp();
	}

	/**
	 * End test
	 */
	public function tearDown(): void {
		Mockery::close();
		parent::tearDown();
	}

}

Первый тест Hard Dependency

Пример тестируемого класса:

function bird_say(): string {
   $duck = new \Bird\Duck();
   return $duck->say();
}

Создаем заглушку для класса \Bird\Duck:

$mock = Mockery::mock( 'Bird\Duck' );
$mock->shouldReceive('say')
    ->once()
    ->andReturn( 'krya' );

Заглушку мы не можем передать в тестируемую функцию исходя из задачи. Но мы можем ее переопределить с помощью overload в библиотеке Mockery:

public function test_bird_say() {
    $mock = Mockery::mock( 'overload:Bird\Duck' );
    $mock->shouldReceive('say')
        ->once()
        ->andReturn( 'krya' );

    $this->assertSame( 'krya', bird_say() );
}

Тест работает, но теперь все объекты Bird\Duck в тестовом классе, которые идут после тестового метода будут иметь такую же заглушку. Это очень плохо так как следующий пример вызывает ошибку из-за того, что Bird\Duck в тесте test_bird_say_2 уже объявлен. Этого быть не должно.

public function test_bird_say() {
    $mock = Mockery::mock( 'overload:Bird\Duck' );
    $mock->shouldReceive('say')
        ->once()
        ->andReturn( 'krya' );

    $this->assertSame( 'krya', bird_say() );
}

public function test_bird_say_2() {
    $mock = Mockery::mock( 'overload:Bird\Duck' );
    $mock->shouldReceive('say')
        ->once()
        ->andReturn( 'no-krya' );

    $this->assertSame( 'no-krya', bird_say() );
}

Первый хороший тест Hard Dependency

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

/**
 * @runInSeparateProcess
 * @preserveGlobalState disabled
 */
public function test_bird_say() {
    $mock = Mockery::mock( 'overload:Bird\Duck' );
    $mock->shouldReceive('say')
        ->once()
        ->andReturn( 'krya' );

    $this->assertSame( 'krya', bird_say() );
}

/**
 * @runInSeparateProcess
 * @preserveGlobalState disabled
 */
public function test_bird_say_2() {
    // ...
}
  • @runInSeparateProcess — Указывает, что тест должен выполняться в отдельном процессе PHP;
  • @preserveGlobalState disabled — нужно запретить сохранять глобальное состояние.

Теперь все работает как надо!

Краткий обзор

Для тестирования Hard Dependencies нам нужно сделать следующее:

  • Установить Mockery
  • Обновить фикстуры в тестовом классе
  • При создании заглушки добавить overload
  • Добавить аннотации к тестируемому методу

Источник: WP Punk.

ВКонтакте
Одноклассники
Linkedin
Telegram
WhatsApp

Автор: Кобзарёв Михаил

Суровый русский тимлид. Жил в Магадане, в офисе московских веб студий и в Тульской деревне. Виртуозно знает WordPress, PHP, ООП, Vue.js и вот это вот все.

Делает крутые высоконагруженные сайты, поэтому уже почти захватил весь рынок WordPress разработки в России. Не дает никому делать сайты без спроса.

Ведет блог о разработке, дайджест в телеграмме и в ВК.

Комментарии
Следующая запись