PHP Conference Japan 2020の登壇資料です。 https://phpcon.php.gr.jp/2020/
微妙な違いも⾒逃すな!ビジュアルリグレッションテスト!PHP Conference Japan 20202020.12.12Yuta Ohashi
View Slide
blue_goheimochi⼤橋 佑太株式会社オウケイウェイヴPHP(Laravel), JavaScript(Vue.js/Nuxt.js),ランニング, サッカー, フットサル,浜松まつり, ポケモンカードゲーム,さわやかのげんこつハンバーグおおはし ゆうた
3⽬次• ビジュアルリグレッションテストとは?• Atomic Designで考えるUIコンポーネント設計• UIコンポーネントのカタログ化• テストのためのツール• CI環境を含めたテストの全体像• よかったこと&改善できそうなこと• やってみて感じた導⼊障壁• まとめ
ビジュアルリグレッションテストとは?
5ビジュアルリグレッションテストとは?• 「⾒た⽬」の変更を検出するためのテスト• 対象はページ全体やUIコンポーネント• 今回はUIコンポーネントの事例をお話しします• 変更前と変更後のスクリーンショットを⽐較して差分を確認することで、意図しない崩れを検知できる
6ビジュアルリグレッションテストとは?どこが変わっているでしょうか?Before After
7ビジュアルリグレッションテストとは?微妙な違いも⾒逃さなかった!Before Afterリンクテキストの⾊変更&アンダーライン追加
8Before Afterビジュアルリグレッションテストとは?微妙な違いも⾒逃さなかった!リンクテキストの⾊変更&アンダーライン追加
Atomic Designで考えるUIコンポーネント設計
10Atomic Designで考えるUIコンポーネント設計Atomic Designとは?
11Atomic Designで考えるUIコンポーネント設計Atomic Designとは?
12Atomic Designで考えるUIコンポーネント設計Atomic Designとは?• Bread Frostさんが考案した、デザインシステム• UIの構造を5段階で表しているのが特徴• Atoms(原⼦)が集まってMolecule(分⼦)に、Moleculesが集まってOrganism(有機体)に、Organismsが集まって‧‧‧‧Pageができる• Webページの要素を分解して、⼩さい部品の組み合わせ(UIコンポーネント)と考える• Vue.jsやReactなどのコンポーネントシステムとも相性が良い
UIコンポーネントのカタログ化
14UIコンポーネントのカタログ化Storybook
15UIコンポーネントのカタログ化Storybook• コンポーネントをカタログのような形で管理‧閲覧できようにするためのツール• 定義ファイルを⽤意することで、コンポーネント1つ1つがWebブラウザから閲覧可能になる• Vue.js、React、Angularなど主要なフレームワークに対応
テストのためのツール
17テストのためのツール• Storycap• reg-suit
18テストのためのツールStorycap
19テストのためのツールStorycap• Storybookをクロールしてスクリーンショットを撮ってくれるツール• 指定したディレクトリに、取得結果を出⼒してくれる
20テストのためのツールreg-suit
21テストのためのツールreg-suit• 画像の⽐較をしてくれるツール• Storycapで取得したスクリーンショットを変更前‧変更後のもので⽐較する• 差分の結果をHTMLで⽣成してくれる
22テストのためのツールStorycapでコンポーネントのスクリーンショットを取得Before After
23Before Afterテストのためのツールreg-suitでBeforeとAfterのスクリーンショットを⽐較リンクテキストの⾊変更&アンダーライン追加
CI環境を含めたテストの全体像
25CI環境を含めたテストの全体像AWS• CodeBuild (AWS CodeBuild)• Storybookのビルド、Storycapでのキャプチャ取得、reg-suitで⽐較、などなど⼀連の操作‧指⽰をする• S3 (Amazon Simple Storage Service)• ビルドしたStorybook、reg-suitでの⽐較結果を保存する• ECR (Amazon Elastic Container Service)• Storycapでスクリーンショットを取得するために、Chromiumをインストールしたコンテナイメージを事前にpushする
26CI環境を含めたテストの全体像前提• CI環境• AWS• CodeBuild• S3• ECR• リポジトリ• Github Enterprise
27CI環境を含めたテストの全体像1. プルリクエスト作成をトリガーにテストが開始される• CodeBuildを呼び出しテストを開始2. Storybookをビルド3. Storycapでスクリーンショットを取得4. reg-suitで前の結果と今回の結果を⽐較する• 前の結果=プルリクエスト対象ブランチがマージされた際に作成されたスクリーンショット5. テスト結果をプルリクエストにコメントする
28CI環境を含めたテストの全体像CodeBuildGithub Enterprise作業内容をGithub EnterpriseにPushする。git pushECRS3Storybook⽤BucketChromiumが⼊ったコンテナイメージ前回のStorybookのスクリーンショット
29CI環境を含めたテストの全体像CodeBuildGithub Enterpriseプルリクエストを作成する。pull requestECRS3Storybook⽤BucketChromiumが⼊ったコンテナイメージ前回のStorybookのスクリーンショット
30CI環境を含めたテストの全体像CodeBuildGithub EnterpriseGithub EnterpriseからのWebhookを経由して、CodeBuildが実⾏される。この際、buildspeck.ymlに記述されている内容を実⾏する。Notify(Webhook)ECRS3Storybook⽤BucketChromiumが⼊ったコンテナイメージ前回のStorybookのスクリーンショット
31CI環境を含めたテストの全体像CodeBuildGithub EnterpriseECRに登録してある、ビジュアルリグレッションテスト⽤のコンテナイメージ(Chromiumなどの必要ツールが⼊っている)をdocker pullするECRS3Storybook⽤BucketChromiumが⼊ったコンテナイメージ前回のStorybookのスクリーンショットdocker pull
32CI環境を含めたテストの全体像CodeBuildGithub EnterpriseStorybookをビルドする(npm run storybook-build)。コンテナはボリュームマウントして実⾏する形にしているので、ビルド成果物はコンテナの外に出⼒される。build StorybookECRS3Storybook⽤BucketChromiumが⼊ったコンテナイメージ前回のStorybookのスクリーンショット
33CI環境を含めたテストの全体像CodeBuildGithub EnterpriseStorycapがChromiumを利⽤し、Storybook全体をクローリングしつつ各UIコンポーネントのスクリーンショットを1つ1つ取得する。CrawlTake screenshotsECRS3Storybook⽤BucketChromiumが⼊ったコンテナイメージ前回のStorybookのスクリーンショット
34CI環境を含めたテストの全体像CodeBuildGithub EnterpriseS3から⽐較対象となる前回のStorybookのスクリーンショットをダウンロードする。Download prev screenshotsECRS3Storybook⽤BucketChromiumが⼊ったコンテナイメージ前回のStorybookのスクリーンショット
35CI環境を含めたテストの全体像CodeBuildGithub Enterprisereg-suitで、今回のStorybookのスクリーンショットと前回のStorybookのスクリーンショットの差分を取り、HTMLレポートを⽣成する。ECRS3Storybook⽤BucketChromiumが⼊ったコンテナイメージ前回のStorybookのスクリーンショットrun reg-suit
36CI環境を含めたテストの全体像CodeBuildGithub EnterpriseStorybook、スクリーンショット、reg-suitのHTMLレポートはアーティファクト(CodeBuildの成果物)として、S3にアップロードする。ECRS3Storybook⽤BucketChromiumが⼊ったコンテナイメージ前回のStorybookのスクリーンショット今回のStorybookのビルド成果物今回のStorybookのスクリーンショット今回のreg-suitのHTMLレポートUpload artifacts
37CI環境を含めたテストの全体像CodeBuildGithub Enterprise結果をプルリクエストにコメントする。ECRS3Storybook⽤BucketChromiumが⼊ったコンテナイメージ前回のStorybookのスクリーンショット今回のStorybookのビルド成果物今回のStorybookのスクリーンショット今回のreg-suitのHTMLレポートComment to pull request
38CI環境を含めたテストの全体像1. プルリクエスト作成をトリガーにテストが開始される• CodeBuildを呼び出しテストを開始2. Storybookをビルド3. Storycapでスクリーンショットを取得4. reg-suitで前の結果と今回の結果を⽐較する• 前の結果=プルリクエスト対象ブランチがマージされた際に作成されたスクリーンショット5. テスト結果をプルリクエストにコメントする
39CI環境を含めたテストの全体像テストが完了するとこんなコメントがプルリクエストにつきます
40CI環境を含めたテストの全体像テストが完了するとこんなコメントがプルリクエストにつきますS3にアップロードされたStorybookのURL
41CI環境を含めたテストの全体像テストが完了するとこんなコメントがプルリクエストにつきますS3にアップロードされたStorybookのURLS3にアップロードされたreg-suitのレポートのURL
42CI環境を含めたテストの全体像テストが完了するとこんなコメントがプルリクエストにつきます変更されたコンポーネント追加されたコンポーネント削除されたコンポーネント変更がなかったコンポーネントが分かる!S3にアップロードされたStorybookのURLS3にアップロードされたreg-suitのレポートのURL
よかったこと&改善できそうなこと
44よかったこと&改善できそうなことよかったこと• レビューがとてもしやすくなった• CSSのリファクタリングがしやすくなった• 意図しない崩れが起きづらくなった
45よかったこと&改善できそうなことよかったこと変更されたコンポーネント追加されたコンポーネント削除されたコンポーネント変更がなかったコンポーネントが分かる!S3にアップロードされたStorybookのURLS3にアップロードされたreg-suitのレポートのURL
46よかったこと&改善できそうなことよかったこと• レビューがとてもしやすくなった• 対象プルリクエストの修正でコンポーネントを壊していないか?が確認できる(⼿元でStorybookを⽴ち上げて確認しなくてもよい)• レビューする側としてもとても安⼼感がある• 追加‧変更‧削除されたコンポーネントがそれぞれわかるので、コードレビューの補助にもなっている
47よかったこと&改善できそうなことよかったこと• CSSのリファクタリングがしやすくなった• デザイナーから上がってきた声• ビジュアルリグレッションテストで差分がでなければ正しくリファクタリングができたというのが分かる• ⼤胆に修正することができた• ⽬視での確認を減らすことができた
48よかったこと&改善できそうなことよかったこと• 意図しない崩れが起きづらくなった• 「ビジュアルリグレッションテスト」と話してきたが実はあまりデグレが発⽣していない• 全体にかかるようなCSSを修正した場合(line-heightを⼀括で変えるなど)にたまにあるくらい• コンポーネント単位で作成するようになったことにより、変更がコンポーネントの中で閉じるようになったためだと考えている• コンポーネントを組み合わせてページを構成した際に、marginの設定もれなどで要素がくっついてしまうというようなことはあるので、ページ全体に対してのテストもうまくできるように考えていきたい
49よかったこと&改善できそうなこと改善できそうなこと• 不安定なコンポーネントを減らす• テストの実⾏時間を短くする• UIコンポーネント設計が難しい
50よかったこと&改善できそうなこと改善できそうなこと• 不安定なコンポーネントを減らす• ⾮同期読み込みがあるようなコンポーネントはStorycapのスクリーンショット取得のタイミングによって変更してないのに差分が出てきてしまうことがある• ⽇付に依存しているコンポーネント
51よかったこと&改善できそうなこと改善できそうなこと• テストの実⾏時間を短くする• 1回のテストに10分前後かかってしまっている• Dockerコンテナ経由でのビルドをしないようにする• テストの並列実⾏• 開発フローの⾒直し
52よかったこと&改善できそうなこと改善できそうなこと• UIコンポーネント設計が難しい• 基本的にはAtomic Designに則ってコンポーネント設計をしている• 最⼩単位のAtomは分かりやすい• これはMolecule?これはOrganism?と複数のコンポーネントを組み合わせたものをどこに配置するかよく相談している• 5つの段階だと少ない‧‧‧• 試験的にOrganismのコンポーネントをページ別に分けて運⽤してみたりしているがまだまだ改善の余地がありそう
やってみて感じた導⼊障壁
54やってみて感じた導⼊障壁• フロントエンド‧バックエンドの開発の分離• デザイナーとの共創
55やってみて感じた導⼊障壁フロントエンド‧バックエンド開発の分離• 組織が分かれている必要はないかもしれないが、コード上でフロントエンドとバックエンドが分かれている必要はありそう• 既存のプロダクトにシュッといれられるかというとつらそう‧‧‧• 今回の事例では、アプリケーションのリプレイスを進めているプロダクトだったということは導⼊障壁をかなり下げていると思われる• フロントエンドはNuxt.js、バックエンドはLaravelという技術選定から⾏えた• この辺りの開発体制を調整するのにすごく⼒を割いた
56やってみて感じた導⼊障壁デザイナーとの共創• フロントエンドチームができることにより、デザイナーとより協⼒(1つのチームとして機能すること)が必要• Atomic Designなどの知識共有、⽂化の共有• 同じリポジトリを利⽤しての開発• 開発側としてもよりUIやデザインといった領域を知る必要がある• サンプルリポジトリを作ったり、トレーニング、情報共有などを⾏った
まとめ
58まとめ• ビジュアルリグレッションテストは「⾒た⽬」をテストする• 今回はUIコンポーネントのテストを紹介• Atomic Designを取り⼊れUIコンポーネント設計を⾏い、StorybookでUIコンポーネントカタログを作成• Storycap、reg-suit、CodeBuild、S3、ECRを使ってテスト環境を構築• レビューがとてもしやすくなった!• 意図しない変更を検知しプルリクエスト上で確認できる• 意図した変更(追加‧変更‧削除)も分かるのでコードレビューの補助となる• ただし、導⼊障壁はやや⾼いと感じている
微妙な違いも⾒逃さなかった!ビジュアルリグレッションテスト!