UI (E2E, GUI) тесты полностью эмулируют поведение пользователей в браузере. Данные тесты относятся к приемочному(acceptance) виду тестирования. Пишется пошаговый тест, как пользователь должен себя вести в вашем приложении: на какую страницу приложения он зайдет, какую информацию заполнит, какую кнопку нажмет и т.д. Чаще всего такие тесты пишут тестировщики, но иногда и разработчики в зависимости от требований компании. В дальнейшем эти тесты можно и даже нужно использовать как часть процесса CI (Continuous Integration).
Данный вид тестов дает 100% гарантию, что ваше приложение работает полностью начиная от сервера, бэкенда и заканчивая фронтендом. К тому же сами тесты мега-простые в написании. Звучит хорошо, но как всегда за это нужно чем-то пожертвовать. Итак, эти тесты не показывают проблемы в коде (за исключением скриншотов, при включенном дебаге) и они слишком долго выполняются, так как требуют ресурсов для запуска.
Так как это единственные тесты, которые дают 100% гарантию работы вашего приложения, они обязательно должны быть на любом продуктовом проекте. Даже 1 тест даст вам крутой результат, а там где 1, там и 10к тестов, которые будут запускаться несколько часов, но реальные люди все равно не смогут протестировать этот же объем вручную и без ошибок.
Установка и настройка Codeception
Установим библиотеку для PHP Codeception, через которую, можно запускать практически любые виды тестов. К нему нужно поставить дополнение WP Browser, которое поможет писать тесты для WordPress еще проще, хотя куда еще проще, эти тесты и так самые простые в написании.
composer require --dev codeception/codeception
composer require --dev lucatume/wp-browser
Из-за того, что библиотека Codeception позволяет запускать различные виды тестов нам понадобиться два конфига: основной и для приемочных тестов. Итак, создаем в корне приложения файл codeception.yml
:
paths:
tests: tests/php # директория с тестами
output: codeception/_output # директория для вывода результатов запуска. В нее будут сохраняться скриншоты и HTML-страницы неудачных запусков, информация по покрытию и многое другое.
data: codeception/_data # дополнительная директорию, куда мы разместим дамп базы данных в дальнейшем.
support: codeception/_support # директория в которую вы можете добавить любые классы (соблюдая стандарт PSR-4), которые будут загружаться при запуске тестов.
envs: codeception/_envs # директория для конфигураций среды разработки.
actor_suffix: Tester # суффикс класса для тестеров.
extensions: # можем подключить любые расширения.
enabled:
- CodeceptionExtensionRunFailed # расширение для продолжения работы при неудачном тесте.
params:
- codeception/_config/params.php # добавляем путь к PHP-файлу, в котором мы пропишем константы для подключения к БД
settings: # настройки запуска
backup_globals: false # запрещаем PHPUnit выполнять резервное копирование глобальных переменных.
colors: true # Делаем разноцветный вывод
Теперь создаем конфиг для приемочных тестов tests/acceptance.suite.yml
:
actor: AcceptanceTester
extensions:
enabled:
- CodeceptionExtensionRunProcess:
0: chromedriver --url-base=/wd/hub
- CodeceptionExtensionRunFailed
commands:
- CodeceptionCommandGenerateWPUnit
- CodeceptionCommandGenerateWPRestApi
- CodeceptionCommandGenerateWPRestController
- CodeceptionCommandGenerateWPRestPostTypeController
- CodeceptionCommandGenerateWPAjax
- CodeceptionCommandGenerateWPCanonical
- CodeceptionCommandGenerateWPXMLRPC
modules:
enabled:
- WPDb
- WPWebDriver
config:
WPDb:
dsn: 'mysql:host=%DB_HOST%;dbname=%DB_NAME%'
user: '%DB_USER%'
password: '%DB_PASSWORD%'
#import the dump before the tests; this means the test site database will be repopulated before the tests.
dump: 'codeception/_data/dump.sql'
populate: true
# re-import the dump between tests; this means the test site database will be repopulated between the tests.
cleanup: true
waitlock: 10
url: '%WP_URL%'
urlReplacement: true
tablePrefix: '%DB_TABLE_PREFIX%'
WPWebDriver:
url: '%WP_URL%'
port: 9515
window_size: maximize
browser: chrome
host: localhost
adminUsername: '%WP_ADMIN_USERNAME%'
adminPassword: '%WP_ADMIN_PASSWORD%'
adminPath: '%WP_ADMIN_PATH%'
capabilities:
"goog:chromeOptions":
args: ["--user-agent=wp-browser"]
Выглядит страшно, но в целом интуитивно понятные настройки. Если есть желание, можете разобраться с настройками сами.
Создаем отдельную новую базу acceptance_db
, ставим чистую установку WordPress, активируем тестируемый плагин/тему и делаем экспорт базы в codeception/_data/dump.sql
. Можно сделать вручную или с помощью WP CLI:
wp config create --dbname="acceptance_db" --dbusroot" --dbpass="root" --dbhost="localhost" --dbprefix="wp_"
wp core install --url="http://your-site.local" --title="Test" --admin_user="admin" --admin_password="pass" --admin_email="i@wp-punk.com" --skip-email
wp rewrite structure '/%postname%/' --hard
wp plugin activate --all
mysqldump --host="localhost" --user="root" --password="root" acceptance_db > codeception/_data/dump.sql
Создаем конфиг для подключения к БД в codeception/_config/params.php
:
<?php
return [
'WP_URL' => 'http://your-site.local',
'WP_ADMIN_USERNAME' => 'admin',
'WP_ADMIN_PASSWORD' => 'pass',
'WP_ADMIN_PATH' => '/wp-admin',
'DB_HOST' => 'localhost',
'DB_NAME' => 'acceptance_db',
'DB_USER' => 'root',
'DB_PASSWORD' => 'root',
'DB_TABLE_PREFIX' => 'wp_',
];
Создаем тестера, который будет выполнять наши задачи в файле codeception/_support/AcceptanceTester.php
:
<?php
use CodeceptionActor;
class AcceptanceTester extends Actor {
use _generatedAcceptanceTesterActions;
}
Теперь обновим wp_config.php
, чтобы при запуске приемочных тестов они выполнялись на другой базе данных:
if (
isset( $_SERVER['HTTP_X_TESTING'] )
|| ( isset( $_SERVER['HTTP_USER_AGENT'] ) && $_SERVER['HTTP_USER_AGENT'] === 'wp-browser' )
|| getenv( 'WPBROWSER_HOST_REQUEST' )
) {
define( 'DB_NAME', 'codeception_db' );
} else {
define( 'DB_NAME', 'local' );
}
С настройкой Codeception мы закончили, но…
Но необходимо установить ChromeDriver:
- MacOS:
brew cask install chromedriver
. - Windows:
choco install chromedriver
Первый Acceptance Тест
Теперь создаем файл tests/acceptance/FirstCest.php
(Cest — суффикс по умолчанию для названия тестовых классов):
<?php
class FirstCest {
public function visitSettingsPage( AcceptanceTester $I ) {
$I->loginAsAdmin();
$I->amOnPage( '/wp-admin/admin.php?page=plugin-name' );
$I->see( 'Plugin Name Settings' );
}
}
Вот так выглядит простой тест, который можно понять и без навыков программирования. Пользователь(I) заходит какую-то страницу в админку и видит там надпись Plugin Name Settings.
Запуск тестов
vendor/bin/codecept run acceptance
При запуске, должно открыться новое окно Google Chrome, автоматически выполнить все действия, описанные в тестах и вывести результат в консоль:
Как видите, самое сложное — это настройка среды, сами тесты очень простые и понятные без особых навыков.
Запуск приемочных тестов в GitHub Actions
Для запуска тестов необходимо настроить локальный сервер. Для этого создаем конфиг для Apache .github/workflows/plugin-name.conf
:
<VirtualHost *:80>
DocumentRoot /home/runner/work/WPPlugin/WPPlugin/wordpress
ServerName plugin-name.test
ErrorLog /home/runner/work/WPPlugin/WPPlugin/logs/error.log
CustomLog /home/runner/work/WPPlugin/WPPlugin/logs/access.log combined
DirectoryIndex index.php index.html /index.php
<Directory /home/runner/work/WPPlugin/WPPlugin/wordpress>
DirectoryIndex index.php index.html /index.php
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
Теперь нужно как-то разделить локальный запуск и запуск во время выполнение CI в GitHub Actions. Поэтому меняем код в файле codeception/_config/params.php
:
<?php
if ( in_array( 'github-actions', $argv, true ) && file_exists( $config ) ) {
// Config for GH Actions.
return [
'WP_URL' => 'http://plugin-name.test',
'WP_ADMIN_USERNAME' => 'admin',
'WP_ADMIN_PASSWORD' => 'admin',
'WP_ADMIN_PATH' => '/wp-admin',
'DB_HOST' => '127.0.0.1',
'DB_NAME' => 'test_db',
'DB_USER' => 'user',
'DB_PASSWORD' => 'passw0rd',
'DB_TABLE_PREFIX' => 'wp_',
];
}
return [
'WP_URL' => 'http://your-site.local',
'WP_ADMIN_USERNAME' => 'admin',
'WP_ADMIN_PASSWORD' => 'pass',
'WP_ADMIN_PATH' => '/wp-admin',
'DB_HOST' => 'localhost',
'DB_NAME' => 'acceptance_db',
'DB_USER' => 'root',
'DB_PASSWORD' => 'root',
'DB_TABLE_PREFIX' => 'wp_',
];
Создаем конфиг для GH Actions .github/workflows/plugin-name.yml
:
name: PluginName GitHub Actions
on: [push]
jobs:
build:
strategy:
matrix:
php-versions: [7.4]
runs-on: ubuntu-latest
env:
php-ext-cache-key: cache-v1 # can be any string, change to clear the extension cache.
php-extensions: mysql
php-ini-values: post_max_size=256M
wp-directory: wordpress
wp-plugins-directory: wordpress/wp-content/plugins
DB_HOST: 127.0.0.1
DB_TABLE_PREFIX: wp_
DB_NAME: test_db
DB_USER: user
DB_PASSWORD: passw0rd
WP_URL: http://plugin-name.test
WP_DOMAIN: plugin-name.test
WP_ADMIN_USERNAME: admin
WP_ADMIN_PASSWORD: admin
WP_ADMIN_EMAIL: admin@plugin-name.test
services:
mysql:
image: mysql:5.6
env:
MYSQL_USER: ${{ env.DB_USER }}
MYSQL_PASSWORD: ${{ env.DB_PASSWORD }}
MYSQL_DATABASE: ${{ env.DB_NAME }}
MYSQL_ALLOW_EMPTY_PASSWORD: yes
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- name: Download Plugin
uses: actions/checkout@v2
with:
path: ${{ env.wp-plugins-directory }}
- name: Install dependencies
working-directory: ${{ env.wp-plugins-directory }}
run: |
composer install
yarn install
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
tools: pecl
php-version: ${{ matrix.php-versions }}
extensions: ${{ env.php-extensions }}
ini-values: ${{ env.php-ini-values }}
env:
update: true
- name: Install WP CLI
run: |
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
chmod +x wp-cli.phar
mkdir -p wp-cli
sudo mv wp-cli.phar wp-cli/wp
echo "::add-path::$GITHUB_WORKSPACE/wp-cli"
echo -n "apache_modules:n - mod_rewrite" > "${{ env.wp-directory }}/wp-cli.yml"
- name: Install WP
working-directory: ${{ env.wp-directory }}
run: |
wp core download --version=5.4
wp config create --dbname="${{ env.DB_NAME }}" --dbuser="${{ env.DB_USER }}" --dbpass="${{ env.DB_PASSWORD }}" --dbhost="${{ env.DB_HOST }}" --dbprefix="${{ env.DB_TABLE_PREFIX }}"
wp core install --url="${{ env.WP_URL }}" --title="Test" --admin_user="${{ env.WP_ADMIN_USERNAME }}" --admin_password="${{ env.WP_ADMIN_PASSWORD }}" --admin_email="${{ env.WP_ADMIN_EMAIL }}" --skip-email
wp rewrite structure '/%postname%/' --hard
wp plugin activate --all
- name: Make a DB dump for Codeception
working-directory: ${{ env.wp-plugins-directory }}
run: mysqldump --host="${{ env.DB_HOST }}" --user="${{ env.DB_USER }}" --password="${{ env.DB_PASSWORD }}" ${{ env.DB_NAME }} > codeception/_data/dump.sql
- name: Setup hosts
run: |
echo ${{ env.DB_HOST }} ${{ env.WP_DOMAIN }} | sudo tee -a /etc/hosts
cat /etc/hosts
- name: Install & configure Apache
run: |
sudo add-apt-repository ppa:ondrej/php
sudo apt-get update
sudo apt-get install apache2 libapache2-mod-php7.4
mkdir -p logs
sudo cp ${{ env.wp-plugins-directory }}/.github/workflows/plugin-name.conf /etc/apache2/sites-available/plugin-name.conf
sudo a2enmod headers
sudo a2enmod rewrite
sudo a2ensite plugin-name
sudo service apache2 restart
- name: Setup Chromedriver
uses: nanasess/setup-chromedriver@master
- name: Run Chromedriver
run: |
export DISPLAY=:99
chromedriver --url-base=/wd/hub &
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 & # optional
- name: Run Acceptance Tests
working-directory: ${{ env.wp-plugins-directory }}
run: .vendor/bin/composer acceptance -- --env github-actions
- name: Archive Codeception output
uses: actions/upload-artifact@v1
if: failure()
with:
name: codeception-output
path: ${{ env.wp-plugins-directory }}/codeception/_output
- name: Archive Apache Logs
uses: actions/upload-artifact@v1
if: failure()
with:
name: apache-logs
path: logs
Теперь, при добавлении нового кода в репозиторий, автоматически запускаются приемочные тесты.