#経緯
「カチカチカチカチカチカチカチカチカチ」
静寂な開発オフィスに響き渡るマウスクリック。それはキーボードのタイプ音よりも顕著である。なぜこんなにもクリック音が鳴り響くのか?それは動作チェックをしているためである。テストは正しく動作するか確認するとても重要な作業だ。
しかし、この作業に一体どれだけの時間を費やすことになるのだろうか。もちろん開発規模によるところであるが、エディタでコード記述→ブラウザで動作確認・・・(LOOP)
これは大きな時間を費やすことになるだろう。インターフェイスもキーボードからマウスに切り替えなければならない。煩雑な作業である。
IT化を提供する立場であるにもかかわらず、アナログな作業をしてしまうのはなんとも皮肉である。そして何より「これはエンジニアらしくない」と感じることとなった。
この問題をどうにかできないだろうか?LaravelにはDuskというブラウザテストを効率よく行うことができる機能がある。今回はその導入について挑戦したときのメモである。
#環境
・Windows
・Laravel 7.30.4
・Docker(nginx1.15.6、php7.4.15、mysql5.7)
かねてよりLaravel開発用のDockerを使っているので、それに加える形での環境更新となる。既に上記のセットで動作している前提となる。mysqlは今回の更新作業に特に関係はしてこない。
#今回の流れ
1. Dockerにseleniumコンテナを追加
2. Composerで「Laravel/Dusk」をインストール
3. LarvelでDusk関係のファイルを作成
4. 動作確認用に「VNC Viewer」をインストール
5. テストしてみる
#1. Dockerにseleniumコンテナを追加
selenium・・・webブラウザでのテストを自動化するツール。DockerHubに公式のイメージがあるのでそれを使う。余談だが、pythonでもこれを介してブラウザ操作ができたりする。
\\追加
selenium:
image: selenium/standalone-chrome-debug
ports:
- 4444:4444
- 5900:5900
depends_on:
- web
privileged: true
今回はデバッグ(テスト)用なので、下記のDebugging部分を参考にした。
ブラウザ操作をするにはdriverが必要だが、Laravelではデフォルトはchromeになっているので、そのままコンテナもchromeにする。
#2. Composerで「Laravel/Dusk」をインストール
次はphpのコンテナでの作業。
docker exec -it phpのコンテナ名 bash
Laravelプロジェクト配下へ移動し、下記コマンドでLaravelDuskをインストールする。
composer require --dev laravel/dusk
ここで今回下記のエラーが出現。phpの拡張機能としてzipが有効になっていない旨の内容。
実は以前php7.4に更新したのだがzipが有効になっていなかったようである。
Your requirements could not be resolved to an installable set of packages.
Problem 1
- laravel/dusk[v6.13.0, ..., 6.x-dev] require ext-zip * -> it is missing fro
m your system. Install or enable PHP's zip extension.
- Root composer.json requires laravel/dusk ^6.13 -> satisfiable by laravel/d
usk[v6.13.0, 6.x-dev].
To enable extensions, verify that they are enabled in your .ini files:
-
- /usr/local/etc/php/conf.d/docker-php-ext-mysqli.ini
- /usr/local/etc/php/conf.d/docker-php-ext-pdo_mysql.ini
- /usr/local/etc/php/conf.d/docker-php-ext-pdo_pgsql.ini
- /usr/local/etc/php/conf.d/docker-php-ext-sodium.ini
You can also run `php --ini` inside terminal to see which files are used by PHP
in CLI mode.
Installation failed, reverting ./composer.json and ./composer.lock to their orig
inal content.
下記コマンドでzip有無を確認するも有効でないようである。
一旦コンテナ内での作業は中止でDockerfileを修正する。
php --ri zip
Extension 'zip' not present.
phpコンテナ用のDockerfileも更新する。RUN apt-getの際、インストールするパッケージを追加した。
zlib1g-dev、libzip-dev、docker-php-ext-install zip
の3つを追加。
RUN apt-get update \
&& apt-get install -y \
git \
zlib1g-dev \
libzip-dev \
zip \
unzip \
vim \
&& docker-php-ext-install zip
変更後コンテナコンテナを再構築する。
docker-compose build
再度コンテナ内に入り、zipの再確認。無事有効になっている。
php --ri zip
zip
Zip => enabled
Zip version => 1.15.6
Libzip headers version => 1.5.1
Libzip library version => 1.5.1
再度LaravelDuskをインストール。無事インストール完了。
composer require --dev laravel/dusk
#3. LarvelでDusk関係のファイルを作成
引き続きphpコンテナでの作業。Laravelプロジェクト配下で書きのコマンドでDusk関係のファイルを作成する。
php artisan dusk:install
無事完了するとtestsディレクトリにBrowserディレクトリとDuskTestCase.phpが作成される。
#4. 動作確認用に「VNC Viewer」をインストール
せっかくなのでテスト実行中の様子を確認したい。したがってVNC Viewerを使ってコンテナ内で実行されるテストの様子を確認できるようにする。ちなみにテストの実行自体はViewerなくてもできる。
下記からインストール。
インストールしたらDockerで指定したlocalhost:5900で接続。passwordを要求されるが、公式通りデフォルトは「secret」でログインできる。
#5. テストしてみる
Dusk作成時にサンプルテストが出来上がっている。HomeにアクセスしたらLaravelのWelcomeが画面が表示されるかというシンプルなテスト。
<?php
namespace Tests\Browser;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;
class ExampleTest extends DuskTestCase
{
/**
* A basic browser test example.
*
* @return void
*/
public function testBasicExample()
{
$this->browse(function (Browser $browser) {
$browser->visit('/')
->assertSee('Laravel');
});
}
}
下記のコマンドでテスト実行。
php artisan dusk
ところが下記のようなエラーになった。どうやらルートURLの設定がうまくできていないようである。
ちなみにエラーはtests/Browser/screenshotsにエラー時点のスクショができる。そして無事にテスト追加すると自動で削除される。
PHPUnit 8.5.14 by Sebastian Bergmann and contributors.
E 1 / 1 (100%)
Time: 1.56 seconds, Memory: 18.00 MB
There was 1 error:
1) Tests\Browser\ExampleTest::testBasicExample
Facebook\WebDriver\Exception\UnknownErrorException: unknown error: net::ERR_CONNECTION_REFU
SED
(Session info: chrome=88.0.4324.96)
/var/www/html/app/laravel/vendor/php-webdriver/webdriver/lib/Exception/WebDriverException.p
hp:139
/var/www/html/app/laravel/vendor/php-webdriver/webdriver/lib/Remote/HttpCommandExecutor.php
:371
/var/www/html/app/laravel/vendor/php-webdriver/webdriver/lib/Remote/RemoteWebDriver.php:604
/var/www/html/app/laravel/vendor/php-webdriver/webdriver/lib/Remote/RemoteExecuteMethod.php
:27
/var/www/html/app/laravel/vendor/php-webdriver/webdriver/lib/WebDriverNavigation.php:41
/var/www/html/app/laravel/vendor/laravel/dusk/src/Browser.php:153
/var/www/html/app/laravel/tests/Browser/ExampleTest.php:19
/var/www/html/app/laravel/vendor/laravel/dusk/src/Concerns/ProvidesBrowser.php:68
/var/www/html/app/laravel/tests/Browser/ExampleTest.php:21
ERRORS!
Tests: 1, Assertions: 0, Errors: 1.
baseUrl()をオーバーライドするとことで対応。webはDockerのnginxコンテナの名前のことである。
<?php
namespace Tests;
use Facebook\WebDriver\Chrome\ChromeOptions;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Laravel\Dusk\TestCase as BaseTestCase;
abstract class DuskTestCase extends BaseTestCase
{
use CreatesApplication;
//追加
protected function baseUrl()
{
return 'http://web';
}
/**
* Prepare for Dusk test execution.
*
* @beforeClass
* @return void
*/
public static function prepare()
{
if (! static::runningInSail()) {
static::startChromeDriver();
}
}
/**
* Create the RemoteWebDriver instance.
*
* @return \Facebook\WebDriver\Remote\RemoteWebDriver
*/
protected function driver()
{
$options = (new ChromeOptions)->addArguments(collect([
'--window-size=1920,1080',
])->unless($this->hasHeadlessDisabled(), function ($items) {
return $items->merge([
'--disable-gpu',
'--headless',
]);
})->all());
return RemoteWebDriver::create(
'http://selenium:4444/wd/hub', DesiredCapabilities::chrome()
);
// return RemoteWebDriver::create(
// $_ENV['DUSK_DRIVER_URL'] ?? 'http://localhost:9515',
// DesiredCapabilities::chrome()->setCapability(
// ChromeOptions::CAPABILITY, $options
// )
// );
}
/**
* Determine whether the Dusk command has disabled headless mode.
*
* @return bool
*/
protected function hasHeadlessDisabled()
{
return isset($_SERVER['DUSK_HEADLESS_DISABLED']) ||
isset($_ENV['DUSK_HEADLESS_DISABLED']);
}
}
再度テスト実行。
php artisan dusk
PHPUnit 8.5.14 by Sebastian Bergmann and contributors.
. 1 / 1 (100%)
Time: 2.09 seconds, Memory: 18.00 MB
OK (1 test, 1 assertion)
無事通過!これで一通りテスト環境が準備できた。公式リファレンスには様々なチェック項目があるのでテストが捗りそう。いろいろ試して行こうと思います。