Slide 1

Slide 1 text

PHPUnitの限界をPlaywright で補完するテストアプローチ 2025年7⽉18⽇ PHPカンファレンス関⻄2025

Slide 2

Slide 2 text

ゆずねり@yuzneri 2025/7/18 2 •バックエンド、たまにフロント エンドもさわる⼈ •技術同⼈誌の執筆 •ドール、ポーカー、謎解き 𝕏:@yuzneri

Slide 3

Slide 3 text

会員登録フォームを作りたい 2025/7/18 3 •会員IDのみのシンプル会員登録 •会員IDにはルールがある •→バリデーションを実装

Slide 4

Slide 4 text

validateメソッドを実装 public function validate(string $memberId) { $errors = []; if (!$this->isAlphanumeric($memberId)) { $errors[] = '英数字のみ利用できます。'; } // 省略 return $errors; } 2025/7/18 4

Slide 5

Slide 5 text

PHPUnit •PHPアプリケーションのテストフレームワーク •PHPで書かれたコードを⾃動テスト •ロジックが正しく動くかどうか 2025/7/18 5

Slide 6

Slide 6 text

PHPUnitテスト public function testInvalidSpecialCharacters() { $controller = new MemberController(); $this->assertContains( '英数字のみ利用できます。', $controller->validate('user@123') ); } 2025/7/18 6

Slide 7

Slide 7 text

画⾯を実装したけどテストは…? 2025/7/18 7

Slide 8

Slide 8 text

⾃動テストの種類 •ユニットテスト(単体テスト) •インテグレーションテスト(結合テスト) •E2Eテスト(End-to-End テスト) 2025/7/18 8

Slide 9

Slide 9 text

⾃動テストのテスト観点 • ユニットテスト • 単⼀のメソッド • 副作⽤がない • インテグレーションテスト • 複数のメソッドを統合 • 副作⽤はあっても良い 2025/7/18 9 • E2Eテスト • システム全体をユーザー⽬線

Slide 10

Slide 10 text

⾃動テストの範囲 2025/7/18 10 アカウント View HTML JS CSS DB アカウント Model 削除メソッド 登録メソッド ユニットテスト アカウント Controller バリデーション メソッド ユニットテスト インテグレーションテスト E2Eテスト

Slide 11

Slide 11 text

PHPUnitでE2Eテストはできる? •ブラウザの挙動を再現できない •JavaScriptの動的処理 •デザイン •クッキーやローカルストレージを伴った画⾯遷移 2025/7/18 11

Slide 12

Slide 12 text

Playwright •マイクロソフト社が開発 •Webサイトのテストフレームワーク •Webブラウザを⾃動操作してテスト 2025/7/18 12

Slide 13

Slide 13 text

Playwrightの特徴 •Chromium、Firefox、WebKitを⾃動操作 •ユーザ⽬線に近い状態でテストできる •Windows、macOS、Linux、Dockerに対応 •Node.jsが⼊っていればすぐに動かせる •CI/CDで⾃動テストがやりやすい 2025/7/18 13

Slide 14

Slide 14 text

Playwrightテスト例 test('testInvalidSpecialCharacters', async ({ page }) => { await page.goto('http://localhost:8080'); await page.getByRole('textbox', { name: '会員ID' }) .fill('user@123'); await page.getByRole('button', { name: '登録' }).click(); await expect(page.locator('.error')) .toContainText('英数字のみ利用できます。'); }); 2025/7/18 14

Slide 15

Slide 15 text

URLを開く page.goto('http://localhost:8080') •ブラウザで指定したURLを開く 2025/7/18 15

Slide 16

Slide 16 text

要素を探す •タグにはロール(役割)が定義されている •例えばだと「textbox」 •PlaywrightのLocatorでロールを指定して要素 を選択する •UIの意味に基づくので壊れにくい 2025/7/18 16

Slide 17

Slide 17 text

Locaterでボタンを探す 登録 2025/7/18 17 getByRole('button', { name: '登録' })

Slide 18

Slide 18 text

Locaterでテキストボックスを探す 会員ID 2025/7/18 18 getByRole('textbox', { name: '会員ID' })

Slide 19

Slide 19 text

フォーム⼊⼒したりボタンを押したり page.getByRole(...).fill(id) page.getByRole(...).click() •fill()はフォーム⼊⼒ •click()はクリック 2025/7/18 19

Slide 20

Slide 20 text

テストする expect(page.locator('.error')) .toContainText('英数字のみ利用できます。') •expect()で要素を指定して •toContainText()で要素を確認する 2025/7/18 20

Slide 21

Slide 21 text

E2Eテストは時間とコストがかかる •テスト時にブラウザが動いている •同じようなテストケースでも時間がかかる • 6ケース実施すると • PHPUnit: 0.017秒 • Playwright: 2.000秒 (Chromiumのみ) •マシンスペックもある程度必要 2025/7/18 21

Slide 22

Slide 22 text

テストピラミッド 2025/7/18 22 E2Eテスト インテグレーション テスト ユニットテスト 速度 速い 遅い コスト ⾼い 低い テストケース

Slide 23

Slide 23 text

PHPUnitの使い所 •ビジネスロジックとアプリケーションルールの テスト •バリデーションロジックを網羅的にテスト •DBにユーザーレコードが作成される 2025/7/18 23

Slide 24

Slide 24 text

Playwrightの使い所 •ユーザーのインタラクションと体験のテスト •なにかしらのバリデーションエラーメッセージが 表⽰される •会員登録完了画⾯まで表⽰される •デザインがくずれていない •テストがないコードのリファクタリング補助 2025/7/18 24

Slide 25

Slide 25 text

まとめ •PHPUnitはバックエンドを検証する礎 •Playwrightはユーザ体験の守護神 •お互いの特徴にあわせて適切に使い分けること で、より安⼼して開発できます 2025/7/18 25