Эта статья была впервые опубликована на https://jaychen.cc/article/34.
Автор Джейчен
Друзья, вы слышали об Энн. . . Нет, вы написали модульные тесты?
Модульное тестирование — неотъемлемая часть процесса разработки.У проекта есть хороший код модульного тестирования, и смелости для рефакторинга гораздо больше. На этот раз я напишу небольшую статью, чтобы представить использование PHPUnit, инструмента модульного тестирования для PHP.
Использование PHPUnit не сложно.Эта статья в основном используется в качестве введения для ознакомления с основными понятиями и использованием.С основой этой статьи будет легче читать документацию на официальном сайте.
Установить
Способ установки PHPUnit очень прост, вы можете установить его одной строкой кода, используя composer.
composer require --dev phpunit/phpunit
После установки вvendor/bin
В каталоге есть исполняемый файл phpunit, который является телом phpunit. Предположим, что структура каталогов нашего проекта выглядит следующим образом:
➜ phpunit tree .
├── controller
├── model
├── service
├── test
└── vendor
├── composer.json
Среди них наш код модульного теста находится в каталоге test. Используйте composer, чтобы решить проблему с автозагрузкой.
{
"autoload": {
"psr-4": {
"Controller\\": "controller/",
"Model\\": "model/",
"Service\\": "service/",
"Test\\": "test/",
}
},
}
Если вы не понимаете использование автозагрузки композитора, вы можете обратиться кэта статья. окончательное исполнениеcomposer dumpautoload -o
Заставьте автозагрузку работать.
На этом наша установка окончена. Если вы используете phpstorm для разработки, то вам необходимо настроить следующее:
Это указывает, где загрузить PHPUnit.Поскольку мы используем композитор для установки, выберите файл autoload.php, сгенерированный композитором для файла здесь.
использовать
Хорошо, допустим, мы сейчас разрабатываем и добавляемCalculateService
файл и написал функцию abs.
namespace Service;
class CalculateService
{
public function abs($num)
{
return abs($num);
}
}
Теперь мыabs
Функция unit test, PHPUnit test указанного класса, должна соответствовать следующим положениям:
- Установка тестовых классов Имя тестирования должно быть заканчивается, должен наследовать
\PHPUnit\Framework\TestCase
базовый класс. - Каждая тестовая функция должна начинаться с test.
Приведенные выше правила должны соблюдаться.Если код не соответствует правилам, PHPUnit не будет рассматривать его как код модульного теста. В дополнение к двум вышеупомянутым, есть несколько хороших привычек кодирования для справки:
- Код модульного теста помещается в каталог test.
- Каждый класс модульного теста начинается с имени тестируемого класса. Например, тестируемый класс
CalculateService
, Тогда классы модульных тестов должны бытьCalculateServiceTest
. - Каждая функция модульного тестирования должна заканчиваться именем тестируемой функции. Например, тестируемая функция
abs
, то функция модульного тестирования должна бытьtestAbs
.
В соответствии с приведенной выше спецификацией напишите код модульного теста
class UserServiceTest extends \PHPUnit\Framework\TestCase
{
public function testAbs()
{
$userService = new \Service\CalculateService();
$this->assertEquals(4, $userService->abs(4));
}
}
В приведенном выше тестовом коде функция, которую мы хотим протестировать, называетсяabs
, а затем утверждать$userService->abs(4)
Результат 4. прямо в phpstormtestAbs
Щелкните правой кнопкой мыши функциюrun UserServiceTest
воплощать в жизнь:
Обнаружено, что в консоль будет выведено следующее
Time: 17 ms, Memory: 4.00MB
OK (1 test, 1 assertion)
показыватьabs
прошедший$userService->abs(4) == 4
Прецедент.Обратите внимание, что это не означает, чтоabs
Функция была протестирована, и хороший тест должен содержать несколько тестовых случаев, чтобы охватить как можно больше возможностей.
Теперь, когда базовые модульные тесты PHPUnit успешно выполнены, вДокументация для PHPUnit, чтобы узнать больше об использовании тестов. Из-за того, что PHPUnit используется слишком часто, мы не можем объяснить их здесь по отдельности.Вот некоторые другие варианты использования.
-
PHPUnit предоставляет
@test
аннотацию, если тестовая функция добавляет@test
аннотация, имя тестовой функции не обязательно должно начинаться с test. -
\PHPUnit\Framework\TestCase
существует одинsetUp
функция, если написанный вами тестовый класс переопределяет эту функцию, то каждый раз перед началом выполнения тестовой функции она будет выполняться первойsetUp
Инициализировать перед тестированием. Аналогично, существует такжеtearDown
Функция, если она переопределена, вызывается после завершения выполнения тестовой функции.tearDown
функция. -
.... Для получения дополнительной информации обратитесь к документации PHPUnit.
файл phpunit.xml
В приведенном выше примере мы используем phpstorm для выполнения тестовых функций одну за другой, но если нам нужно выполнить все модульные тесты одновременно, мы можем написать файл phpunit.xml для этого.
Приведите пример написания phpunit.xml, объясняющий роль phpunit.xml.
<?xml version="1.0" encoding="UTF-8"?>
<phpunit>
<testsuites>
<testsuite>
<directory>test</directory>
</testsuite>
</testsuites>
</phpunit>
здесь<directory>test</directory>
Укажите, что тестовый код находится в тестовом каталоге, щелкните правой кнопкой мыши файл phpunit.xml в разделе phpstorm и выберитеRun phpunit.xml
, phpunit перейдет в каталог test, чтобы найти все модульные тесты и выполнить их один за другим.
В дополнение к использованию phpunit.xml для одновременного выполнения всех модульных тестов, вы также можете настроить выходное журналирование результатов модульных тестов в phpunit.xml.
<?xml version="1.0" encoding="UTF-8"?>
<phpunit>
.....
<logging>
<log type="testdox-html" target="tmp/log.html"/>
</logging>
</phpunit>
На этом этапе при выполнении файла phpunit.xml в каталоге проекта будет создан файл.tmp/log.html
файл, этот файл записывает результаты всех модульных тестов.
Конечно, для получения дополнительной информации, связанной с конфигурацией phpunit.xml, вам все равно нужно проверить документацию. :смеющийся:
Пробный тест
PHPUnit также предоставляет пробные тесты. Вот введение в то, что такое пробный тест.
Предполагая, что функция foo вызывает функцию bar, есть две проблемы с модульным тестированием функции foo:
- Функция foo зависит от результата функции bar, поэтому bar должен быть введен, когда foo тестируется модульно, поэтому субмодульный тест не имеет смысла.Если тест не пройден, нет гарантии, что ошибка находится в foo или bar.
- Функция BAR не может выполняться в тестовой среде, тогда Foo не может получить результат выполнения BAR, поэтому FOO не разрешено модульное тестирование.
Мок-тест, по-видимому, решает указанную выше проблему.Используя Мок, мы можем виртуализировать вызов bar и предположить, что вызов bar возвращает результат. Если вы все еще не понимаете, вы будете знать предыдущий код.
class MockTest extends \PHPUnit\Framework\TestCase {
public function testGet()
{
$stub = $this->createMock(\App\UserService::class); //1
$stub->method('get')->willReturn(3); //2
$this->assertEquals(3,$stub->get(1)); //3
}
}
Приведенная выше тестовая функция использует Mock, который анализируется построчно:
- Первая строка создает фиктивный
UserService
объект. - Вторая строка предполагает
UserService
серединаget
Возвращаемое значение функции равно 3. - Третья линия звонит
$stub->get(1)
на самом деле не будет выполнятьсяget
функцию, а согласно второй строкеwillReturn
Функция возвращает 3 напрямую.
Вышеприведенный простой пробный тест. Конечно, есть много сложных применений пробного теста. Нет возможности расширять их по одному. На самом деле, если вы освоите базовое использование, еще не поздно проверить документации, если на практике вы столкнетесь с более сложными продвинутыми вариантами использования.
Ну вот и все по основным операциям PHPUnit.Само по себе модульное тестирование не является сложной вещью.Это не техническое препятствие прогрессу модульного тестирования,а больше об измерении и учете графика проекта.