JA EN

画像処理の自動テスト手法 - Visual Regression Testing の実践ガイド

· 約 9 分で読めます

Visual Regression Testing とは - 画像の変化を自動検出する仕組み

Visual Regression Testing (VRT) は、Web ページやコンポーネントのスクリーンショットを撮影し、以前のバージョンと比較することで意図しない視覚的変化を検出するテスト手法です。画像処理パイプラインにおいては、圧縮・リサイズ・フォーマット変換後の画像品質を自動的に検証する用途で活用されます。

VRT が解決する問題:

VRT の基本フロー:

VRT は単体テストや結合テストでは検出できない視覚的な問題を捕捉できるため、画像を多用するサイトでは特に価値が高いテスト手法です。

Playwright による VRT の実装 - スクリーンショット比較の基本

Playwright は Microsoft が開発するブラウザ自動化ツールで、組み込みのスクリーンショット比較機能を持っています。追加のライブラリなしで VRT を実装できるため、最も手軽な選択肢です。

基本的なスクリーンショットテスト:

import { test, expect } from '@playwright/test';
test('hero image renders correctly', async ({ page }) => {
await page.goto('/products/123');
await page.waitForLoadState('networkidle');
const heroImage = page.locator('.hero-image');
await expect(heroImage).toHaveScreenshot('hero-image.png', {
maxDiffPixelRatio: 0.01,
});
});

maxDiffPixelRatio: 0.01 は、全ピクセルの 1% まで差分を許容する設定です。画像圧縮のわずかな差異やアンチエイリアシングの違いを吸収するために、ある程度の許容値が必要です。

複数ビューポートでのテスト:

const viewports = [
{ width: 375, height: 667, name: 'mobile' },
{ width: 768, height: 1024, name: 'tablet' },
{ width: 1440, height: 900, name: 'desktop' },
];
for (const vp of viewports) {
test(`image gallery at ${vp.name}`, async ({ page }) => {
await page.setViewportSize({ width: vp.width, height: vp.height });
await page.goto('/gallery');
await expect(page).toHaveScreenshot(`gallery-${vp.name}.png`);
});
}

ダークモードのテスト:

test('images in dark mode', async ({ page }) => {
await page.emulateMedia({ colorScheme: 'dark' });
await page.goto('/blog/article-1');
await expect(page).toHaveScreenshot('article-dark.png');
});

Playwright のスクリーンショット比較は、初回実行時にベースラインを自動生成し、__snapshots__ ディレクトリに保存します。ベースラインの更新は npx playwright test --update-snapshots で実行します。

画像処理パイプラインのテスト - 圧縮品質と出力検証

画像処理パイプライン (リサイズ、圧縮、フォーマット変換) の出力を自動テストする方法を紹介します。VRT とは異なり、ここでは画像ファイル自体のプロパティと品質を検証します。

出力画像のプロパティ検証:

import sharp from 'sharp';
import { describe, it, expect } from 'vitest';
describe('Image pipeline output', () => {
it('generates correct dimensions', async () => {
const metadata = await sharp('output/hero-800.webp').metadata();
expect(metadata.width).toBe(800);
expect(metadata.format).toBe('webp');
});
it('file size is within budget', async () => {
const stats = await fs.stat('output/hero-800.webp');
expect(stats.size).toBeLessThan(100 * 1024); // 100KB 以下
});
});

SSIM による品質検証: 圧縮後の画像品質が閾値を下回っていないことを自動検証します。

import { ssim } from 'ssim.js';
it('maintains quality above threshold', async () => {
const original = await loadImageData('input/photo.jpg');
const compressed = await loadImageData('output/photo.webp');
const { mssim } = ssim(original, compressed);
expect(mssim).toBeGreaterThan(0.95);
});

バッチ処理の整合性テスト: 全入力画像に対して出力が生成されていること、ファイル名の命名規則が正しいこと、必要なフォーマット (AVIF, WebP, JPEG) が全て生成されていることを検証します。

it('generates all required formats', async () => {
const inputs = await glob('src/images/*.{jpg,png}');
for (const input of inputs) {
const base = path.basename(input, path.extname(input));
expect(fs.existsSync(`dist/${base}.avif`)).toBe(true);
expect(fs.existsSync(`dist/${base}.webp`)).toBe(true);
}
});

CI/CD への統合 - GitHub Actions での自動実行

VRT と画像テストを CI/CD パイプラインに統合し、プルリクエストごとに自動実行する構成を紹介します。

GitHub Actions ワークフロー例:

name: Visual Regression Tests
on: [pull_request]
jobs:
vrt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- run: npm ci
- run: npx playwright install --with-deps
- run: npm run build
- run: npx playwright test
- uses: actions/upload-artifact@v4
if: failure()
with:
name: vrt-diff
path: test-results/

ベースラインの管理: スクリーンショットのベースライン画像は Git リポジトリにコミットします。LFS (Large File Storage) の使用を推奨しますが、画像数が少ない場合は通常の Git 管理でも問題ありません。ベースラインの更新は専用のコミットで行い、コードの変更と混ぜないようにします。

差分レポートの生成: テスト失敗時に差分画像 (元画像、新画像、差分ハイライト) をアーティファクトとしてアップロードし、プルリクエストのレビューで確認できるようにします。Playwright は自動的に差分画像を test-results ディレクトリに生成します。

並列実行による高速化: Playwright の --shard オプションで複数のワーカーに分散実行できます。画像の多いサイトでは、ページごとにシャードを分割して並列実行することで、テスト時間を大幅に短縮できます。

フレーキーテスト対策: VRT はフォントレンダリングやアニメーションのタイミングにより、同じコードでも結果が異なる場合があります。animations: 'disabled' オプションでアニメーションを無効化し、Web フォントの読み込み完了を待ってからスクリーンショットを撮影してください。

Percy と reg-suit - クラウドベースの VRT サービス

自前で VRT インフラを構築する代わりに、クラウドベースの VRT サービスを利用する選択肢もあります。ベースライン管理、差分レビュー UI、ブラウザ間比較などの機能が提供されます。

Percy (BrowserStack): BrowserStack が提供するクラウド VRT サービスです。スクリーンショットをクラウドにアップロードし、ブラウザ上で差分をレビューできます。

import percySnapshot from '@percy/playwright';
test('product page', async ({ page }) => {
await page.goto('/products/123');
await percySnapshot(page, 'Product Page');
});

Percy の利点は、複数ブラウザ (Chrome, Firefox, Safari) でのレンダリング差異を一括で検出できる点と、チームでの差分承認ワークフローが組み込まれている点です。無料プランでは月 5,000 スクリーンショットまで利用可能です。

reg-suit: オープンソースの VRT ツールで、スクリーンショットの差分を S3 や GCS にアップロードし、GitHub のプルリクエストにレポートをコメントします。クラウドサービスに依存せず、自前のインフラで運用できる点が特徴です。

npx reg-suit run

reg-suit は reg-keygen-git-hash-plugin でベースラインのコミットハッシュを自動決定し、reg-publish-s3-plugin で差分レポートを S3 にアップロードします。GitHub Actions との統合も容易で、プルリクエストに差分サマリーを自動コメントできます。

選定基準: チーム規模が小さく、テスト対象が限定的な場合は Playwright の組み込み機能で十分です。複数ブラウザでの検証やチームでの承認フローが必要な場合は Percy、コストを抑えつつ柔軟な運用をしたい場合は reg-suit が適しています。

画像パフォーマンステストの自動化 - Lighthouse CI との統合

画像の最適化状態をパフォーマンスの観点から自動テストする方法を紹介します。Lighthouse CI を使えば、画像関連のパフォーマンス指標を継続的に監視できます。

Lighthouse CI の設定:

// lighthouserc.js
module.exports = {
ci: {
collect: { url: ['http://localhost:3000/', 'http://localhost:3000/gallery'] },
assert: {
assertions: {
'uses-webp-images': ['error', { minScore: 1 }],
'uses-responsive-images': ['warn', { minScore: 0.9 }],
'offscreen-images': ['warn', { minScore: 0.9 }],
'unsized-images': ['error', { minScore: 1 }],
}
}
}
};

画像固有のアサーション:

カスタムメトリクスの追加: Lighthouse のカスタム監査を作成し、画像の総転送量が予算 (例: 500KB) を超えていないか、画像リクエスト数が上限 (例: 30 リクエスト) を超えていないかを検証できます。

パフォーマンスバジェットの設定:

{ "resourceSizes": [{ "resourceType": "image", "budget": 500 }],
"resourceCounts": [{ "resourceType": "image", "budget": 30 }] }

これらのテストを CI/CD に統合することで、画像の最適化が退行していないことを継続的に保証できます。新しい画像を追加する際に、最適化されていない画像がデプロイされることを防ぐ安全網として機能します。

関連記事

画像の差分比較手法 - ピクセル単位からセマンティック比較まで

画像の差分を検出・可視化する技術を体系的に解説。ピクセル比較、構造的類似度、知覚的差分など多角的なアプローチを紹介します。

Web サイトの画像パフォーマンス監査 - Core Web Vitals 改善の実践ガイド

Web サイトの画像がパフォーマンスに与える影響を監査する方法を解説。LCP 改善、CLS 防止、転送量削減の具体的な手法を紹介します。

CI/CD パイプラインでの画像最適化自動化 - GitHub Actions と Sharp による実践構成

CI/CD パイプラインに画像最適化を組み込む方法を解説。GitHub Actions での自動変換、Sharp による WebP/AVIF 生成、ファイルサイズの閾値チェックを実装例とともに紹介します。

大量画像の一括処理ワークフロー - 効率的なバッチ処理の設計と実装

数百〜数千枚の画像を効率的に一括処理するワークフローの設計方法を、コマンドラインツールとスクリプトの実例で解説します。

スクリーンショットツール比較 - OS 標準からプロ向けまで徹底解説

Windows、macOS の標準機能から専用ツールまで、スクリーンショットツールを機能・使い勝手・価格で比較。用途に合った最適なツールが見つかります。

スクリーンショット編集のコツ - トリミング、注釈、モザイクの実践テクニック

ブログやドキュメントで使えるスクリーンショットの編集テクニックを、トリミング、注釈追加、個人情報のモザイク処理まで網羅的に解説します。

関連用語