Замена конструкций exit/die в unit-тестах

3 мин. 18 сек.
119
1

Если в коде вы используете die/exit то PHPUnit прекратит свою работу в этот момент. Для этого нам нужно заменить конструкцию exit/die. Но это сделать сложно т.к. Functions Mocker с этим не справляется.

Пример:

class Duck {
 
	public function last_words() {
		die( 'I\'ll be back' );
	}
 
}

Меняем класс следующий образом:

class Duck {
 
	public function last_words() {
		return $this->die( 'I\'ll be back' );
	}

	/**
	 * @codeCoverageIgnore
	 */
	protected function die( $message = '' ) {
		return die( $message );
	}
 
}

Добавляем к методу die() аннотацию @codeCoverageIgnore, чтобы не учитывать при вычислении покрытия тестов

Вместо реального объекта создаем частичного двойника. Затем разрешаем вызов защищенных методов и делаем заглушку для метода die():

use PHPUnit\Framework\TestCase;

class Test_Duck extends TestCase {
 
	public function test_last_words() {
		$duck = \Mockery::mock( Duck::class )->makePartial();
		$duck->shouldAllowMockingProtectedMethods();
		$duck
			->shouldReceive( 'die' )
			->with( 'I\'ll be back' )
			->once()
			->andReturnArg( 0 );

		$this->assertSame( 'I\'ll be back', $duck->last_words() );
	}

}

Это нам может понадобиться после использования редиректов в WordPress, например wp_safe_redirect:

class Some_Class {

	public function some_method() {
		wp_safe_redirect(
			remove_query_arg(
				[ '_wp_http_referer', '_wpnonce' ],
				wp_unslash( $_SERVER['REQUEST_URI'] ) // phpcs:ignore
			)
		);
		$this->exit();
	}
	
	/**
	 * @codeCoverageIgnore
	 */
	protected function exit() {
		exit;
	}

}

И собственно весь тест для этого кода:

use PHPUnit\Framework\TestCase;

use function Brain\Monkey\Functions\expect;

class Test_Some_Class extends TestCase {

	public function test_some_method() {
		$some_url                 = '/some-url/';
		$some_class = \Mockery::mock( \Some_Class::class )->makePartial();
		$some_class->shouldAllowMockingProtectedMethods();
		$some_class
			->shouldReceive( 'exit' )
			->once();
		$_REQUEST['_wp_http_referer'] = 'some-referer';
		$_SERVER['REQUEST_URI']       = $some_url;

		expect( 'wp_safe_redirect' )
			->with( $some_url )
			->once();
		expect( 'remove_query_arg' )
			->with(
				[ '_wp_http_referer', '_wpnonce' ],
				$some_url
			)
			->once()
			->andReturn( $some_url );
		expect( 'wp_unslash' )
			->with(
				$some_url
			)
			->once()
			->andReturn( $some_url );

		$some_class->some_method();
	}
}

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *