Unit Test vs Integration Test
iOSテスト戦略の基盤: 単体を分離するユニットテストか、コンポーネント間のやり取りを検証する統合テストか。テストピラミッドを正しく構築する方法とは?
Microsoftによるマルチブラウザ・多言語対応のE2Eテストエンジン
ブラウザ内で動作する、開発者体験重視のJS/TS E2Eツール
明確な唯一の正解はないが、明確な判断基準はある。マルチブラウザ対応、無料の並列実行、cross-origin/iframeフロー、あるいはJS/TS以外の言語が必要なら、Playwrightが2026年のデフォルトの選択肢だ。 広範で健全なCypressスイートとCloudへの投資が既にあるなら、単なる「ツールの違い」だけでは書き直しは正当化されない — component testingにおいてはCypressの方が今日時点で成熟している。段階的で重要フロー優先の移行の方が「週末で書き直す」よりも合理的だ。
| カテゴリー | Playwright | Cypress |
|---|---|---|
| パフォーマンス | 8/10 | 7/10 |
| 学習のしやすさ | 7/10 | 8/10 |
| エコシステム | 8/10 | 7/10 |
| コミュニティ | 8/10 | 7/10 |
| 求人市場 | 7/10 | 7/10 |
| 将来性 | 9/10 | 6/10 |
// Playwright Test - ログインフローとAPIモック(TypeScript)
import { test, expect } from '@playwright/test';
test.describe('Giris akisi', () => {
test('gecerli kullanici ile giris yapar ve dashboard gorur', async ({ page }) => {
// ネットワークモック - 追加設定不要
await page.route('**/api/login', async (route) => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ token: 'test-token', user: { name: 'Ayse' } }),
});
});
await page.goto('/login');
await page.getByLabel('E-posta').fill('[email protected]');
await page.getByLabel('Sifre').fill('guclu-sifre-123');
await page.getByRole('button', { name: 'Giris Yap' }).click();
// Auto-wait: ロケーターが表示されるまで待機
await expect(page.getByText('Hos geldin, Ayse')).toBeVisible();
await expect(page).toHaveURL('/dashboard');
});
test('checkout iframe icindeki odeme butonunu bulur (cross-frame)', async ({ page }) => {
await page.goto('/checkout');
// v1.63.0: セレクターなしのframeLocatorはすべてのサブフレームツリーを検索
const payButton = page.frameLocator().getByRole('button', { name: 'Ode' });
await payButton.click();
await expect(page.getByText('Odeme basarili')).toBeVisible();
});
});
test('3 tarayicida paralel calisir (playwright.config.ts icinde tanimli)', async ({ page }) => {
await page.goto('/');
await expect(page).toHaveTitle(/Ana Sayfa/);
});// Cypress - ログインフローとAPIモック(JavaScript/TypeScript)
describe('Giris akisi', () => {
it('gecerli kullanici ile giris yapar ve dashboard gorur', () => {
// cy.interceptによるネットワークスタブ
cy.intercept('POST', '/api/login', {
statusCode: 200,
body: { token: 'test-token', user: { name: 'Ayse' } },
}).as('loginRequest');
cy.visit('/login');
cy.get('[data-cy=email]').type('[email protected]');
cy.get('[data-cy=password]').type('guclu-sifre-123');
cy.get('[data-cy=submit]').click();
cy.wait('@loginRequest');
// Cypress自動リトライ: 要素が表示されるまで待機
cy.contains('Hos geldin, Ayse').should('be.visible');
cy.url().should('include', '/dashboard');
});
it('cross-origin odeme sayfasina yonlenir (cy.origin gerekli)', () => {
cy.visit('/checkout');
cy.get('[data-cy=pay-button]').click();
// 異なるoriginに移動する際はcy.origin()が必須
cy.origin('https://pay.example.com', () => {
cy.get('[data-cy=confirm-payment]').click();
cy.contains('Odeme onaylandi').should('be.visible');
});
});
});
// cypress.config.js — 基本的なE2E設定
module.exports = {
e2e: {
baseUrl: 'http://localhost:3000',
experimentalRunAllSpecs: true,
setupNodeEvents(on, config) {
return config;
},
},
};明確な唯一の正解はないが、明確な判断基準はある。マルチブラウザ対応、無料の並列実行、cross-origin/iframeフロー、あるいはJS/TS以外の言語が必要なら、Playwrightが2026年のデフォルトの選択肢だ。 広範で健全なCypressスイートとCloudへの投資が既にあるなら、単なる「ツールの違い」だけでは書き直しは正当化されない — component testingにおいてはCypressの方が今日時点で成熟している。段階的で重要フロー優先の移行の方が「週末で書き直す」よりも合理的だ。
無料相談を受けるマルチブラウザ(Chromium+Firefox+WebKit)が必要な場合、無料の組み込み並列実行を求める場合、またはTS/Python/Java/.NET間の言語の柔軟性が必要な場合は、Playwrightが2026年のデフォルトの選択肢だ。既に広範なCypressスイートがあり、チームがインタラクティブなrunnerに慣れていて、Cypress Cloudに既に投資しているなら、単なる「ツールの違い」だけで移行は正当化されない — 段階的な移行の方が合理的だ。