jpskill.com
🛠️ 開発・MCP コミュニティ

fast-check

fast-checkは、想定外のバグを効率的に見つけるため、大量のランダムなテストデータを自動生成し、TypeScriptで記述されたコードの品質を向上させるproperty-based testingを支援するSkill。

📜 元の英語説明(参考)

Find edge-case bugs with property-based testing using fast-check — generate thousands of random inputs automatically. Use when someone asks to "find edge cases", "fast-check", "property-based testing", "fuzz testing in TypeScript", "generate random test data", "QuickCheck for JavaScript", or "test with random inputs". Covers property definitions, arbitraries, shrinking, model-based testing, and integration with Vitest/Jest.

🇯🇵 日本人クリエイター向け解説

一言でいうと

fast-checkは、想定外のバグを効率的に見つけるため、大量のランダムなテストデータを自動生成し、TypeScriptで記述されたコードの品質を向上させるproperty-based testingを支援するSkill。

※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o fast-check.zip https://jpskill.com/download/14888.zip && unzip -o fast-check.zip && rm fast-check.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/14888.zip -OutFile "$d\fast-check.zip"; Expand-Archive "$d\fast-check.zip" -DestinationPath $d -Force; ri "$d\fast-check.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して fast-check.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → fast-check フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

fast-check

概要

fast-check はプロパティベースのテストフレームワークです。具体的なテストケースを書く代わりに、常に成り立つべきプロパティを記述すると、fast-check はそれらを破ろうと何千ものランダムな入力を生成します。失敗する入力を見つけると、自動的にそれを最小限の再現ケースに縮小します。空文字列、負の数、Unicode、巨大な配列、境界値など、テストすることを考えもしなかったエッジケースを捕捉します。

どのような時に使うか

  • 多数の入力が考えられる関数 (パーサー、バリデーター、シリアライザー)
  • ビジネスロジックにおけるエッジケースの発見 (価格設定、権限、日付処理)
  • シリアライズ/デシリアライズのラウンドトリップテスト (encode → decode = original)
  • 数学的特性の検証 (可換性、結合性)
  • 手書きのテストケースを生成されたテストケースで置き換える

手順

セットアップ

npm install -D fast-check

基本的なプロパティ

// math.test.ts — 数学関数のためのプロパティベーステスト
import fc from "fast-check";
import { describe, it, expect } from "vitest";

describe("sort", () => {
  it("should produce an array of same length", () => {
    fc.assert(
      fc.property(fc.array(fc.integer()), (arr) => {
        const sorted = [...arr].sort((a, b) => a - b);
        return sorted.length === arr.length;
      })
    );
  });

  it("should produce ordered output", () => {
    fc.assert(
      fc.property(fc.array(fc.integer()), (arr) => {
        const sorted = [...arr].sort((a, b) => a - b);
        for (let i = 1; i < sorted.length; i++) {
          expect(sorted[i]).toBeGreaterThanOrEqual(sorted[i - 1]);
        }
      })
    );
  });

  it("should contain the same elements", () => {
    fc.assert(
      fc.property(fc.array(fc.integer()), (arr) => {
        const sorted = [...arr].sort((a, b) => a - b);
        expect(sorted).toEqual(expect.arrayContaining(arr));
        expect(arr).toEqual(expect.arrayContaining(sorted));
      })
    );
  });
});

ラウンドトリップテスト

// serialization.test.ts — エンコード/デコードのラウンドトリップ
import fc from "fast-check";
import { encode, decode } from "./my-codec";

it("decode(encode(x)) === x for any string", () => {
  fc.assert(
    fc.property(fc.string(), (original) => {
      const encoded = encode(original);
      const decoded = decode(encoded);
      expect(decoded).toEqual(original);
    })
  );
});

it("JSON roundtrip preserves data", () => {
  fc.assert(
    fc.property(fc.jsonValue(), (value) => {
      const json = JSON.stringify(value);
      const parsed = JSON.parse(json);
      expect(parsed).toEqual(value);
    })
  );
});

カスタム Arbitraries

// business.test.ts — ドメインオブジェクトのためのカスタムデータジェネレーター
import fc from "fast-check";

// Generate realistic user objects
const userArbitrary = fc.record({
  id: fc.uuid(),
  name: fc.string({ minLength: 1, maxLength: 100 }),
  email: fc.emailAddress(),
  age: fc.integer({ min: 13, max: 120 }),
  role: fc.constantFrom("admin", "user", "viewer"),
  createdAt: fc.date({ min: new Date("2020-01-01"), max: new Date() }),
});

// Generate realistic money amounts
const moneyArbitrary = fc.record({
  amount: fc.integer({ min: 0, max: 1_000_000 }),  // Cents
  currency: fc.constantFrom("USD", "EUR", "GBP"),
});

it("discount should never result in negative price", () => {
  fc.assert(
    fc.property(
      moneyArbitrary,
      fc.integer({ min: 0, max: 100 }),  // Discount percentage
      (price, discountPercent) => {
        const discounted = applyDiscount(price, discountPercent);
        expect(discounted.amount).toBeGreaterThanOrEqual(0);
      }
    )
  );
});

it("total should equal sum of line items", () => {
  fc.assert(
    fc.property(
      fc.array(moneyArbitrary, { minLength: 1, maxLength: 50 }),
      (items) => {
        const total = calculateTotal(items);
        const expected = items.reduce((sum, item) => sum + item.amount, 0);
        expect(total).toBe(expected);
      }
    )
  );
});

Shrinking (自動的な最小再現)

// プロパティが失敗した場合、fast-check は自動的に最小の失敗する入力を探します

it("handles edge cases in URL parsing", () => {
  fc.assert(
    fc.property(fc.webUrl(), (url) => {
      const parsed = parseUrl(url);
      expect(parsed.protocol).toBeTruthy();
      // If this fails on a complex URL, fast-check shrinks it to
      // the simplest URL that still fails, e.g., "http://a"
    })
  );
});

例 1: エッジケースに対するパーサーのテスト

ユーザープロンプト: 「私の CSV パーサーは奇妙な入力で壊れます。すべてのエッジケースを見つけてください。」

エージェントは "parse(serialize(data)) === data" のようなプロパティを記述し、エッジケース (フィールド内のカンマ、改行、空のセル、Unicode) を含むランダムな CSV データを生成し、失敗する入力を特定します。

例 2: 価格設定ロジックの検証

ユーザープロンプト: 「割引計算をテストして、負の価格や丸め誤差が発生しないことを確認してください。」

エージェントはランダムな価格、割引率、およびクーポン組み合わせを生成し、不変条件 (非負、正しい丸め、順序は関係ない) を検証します。

ガイドライン

  • 例ではなく、プロパティで考える — 「ソートされた出力は順序付けられている」ではなく「sort([3,1,2]) = [1,2,3]」
  • ラウンドトリップは最も簡単なプロパティdecode(encode(x)) === x
  • fc.assert はデフォルトで 100 回のイテレーションを実行する{ numRuns: 1000 } で増やす
  • Shrinking は自動 — 失敗した入力は最も単純なケースに最小化される
  • 組み込みの arbitraries はほとんどのニーズをカバーするstring, integer, array, record, date, uuid, emailAddress
  • enums には constantFromfc.constantFrom("a", "b", "c")
  • 事前条件には fc.pre(condition) — 条件を満たさない入力をスキップする
  • 例ベースのテストと組み合わせる — プロパティは未知のものを見つけ、例は既知のものを検証する
  • 再現性のためのシード — 失敗した実行はシードを出力する。同じシードで再実行して再現する
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

fast-check

Overview

fast-check is a property-based testing framework — instead of writing specific test cases, you describe properties that should always hold, and fast-check generates thousands of random inputs to try to break them. When it finds a failing input, it automatically shrinks it to the minimal reproducing case. Catches edge cases you'd never think to test: empty strings, negative numbers, Unicode, massive arrays, boundary values.

When to Use

  • Functions with many possible inputs (parsers, validators, serializers)
  • Finding edge cases in business logic (pricing, permissions, date handling)
  • Testing serialization/deserialization roundtrips (encode → decode = original)
  • Verifying mathematical properties (commutativity, associativity)
  • Replacing hand-written test cases with generated ones

Instructions

Setup

npm install -D fast-check

Basic Properties

// math.test.ts — Property-based testing for math functions
import fc from "fast-check";
import { describe, it, expect } from "vitest";

describe("sort", () => {
  it("should produce an array of same length", () => {
    fc.assert(
      fc.property(fc.array(fc.integer()), (arr) => {
        const sorted = [...arr].sort((a, b) => a - b);
        return sorted.length === arr.length;
      })
    );
  });

  it("should produce ordered output", () => {
    fc.assert(
      fc.property(fc.array(fc.integer()), (arr) => {
        const sorted = [...arr].sort((a, b) => a - b);
        for (let i = 1; i < sorted.length; i++) {
          expect(sorted[i]).toBeGreaterThanOrEqual(sorted[i - 1]);
        }
      })
    );
  });

  it("should contain the same elements", () => {
    fc.assert(
      fc.property(fc.array(fc.integer()), (arr) => {
        const sorted = [...arr].sort((a, b) => a - b);
        expect(sorted).toEqual(expect.arrayContaining(arr));
        expect(arr).toEqual(expect.arrayContaining(sorted));
      })
    );
  });
});

Roundtrip Testing

// serialization.test.ts — Encode/decode roundtrips
import fc from "fast-check";
import { encode, decode } from "./my-codec";

it("decode(encode(x)) === x for any string", () => {
  fc.assert(
    fc.property(fc.string(), (original) => {
      const encoded = encode(original);
      const decoded = decode(encoded);
      expect(decoded).toEqual(original);
    })
  );
});

it("JSON roundtrip preserves data", () => {
  fc.assert(
    fc.property(fc.jsonValue(), (value) => {
      const json = JSON.stringify(value);
      const parsed = JSON.parse(json);
      expect(parsed).toEqual(value);
    })
  );
});

Custom Arbitraries

// business.test.ts — Custom data generators for domain objects
import fc from "fast-check";

// Generate realistic user objects
const userArbitrary = fc.record({
  id: fc.uuid(),
  name: fc.string({ minLength: 1, maxLength: 100 }),
  email: fc.emailAddress(),
  age: fc.integer({ min: 13, max: 120 }),
  role: fc.constantFrom("admin", "user", "viewer"),
  createdAt: fc.date({ min: new Date("2020-01-01"), max: new Date() }),
});

// Generate realistic money amounts
const moneyArbitrary = fc.record({
  amount: fc.integer({ min: 0, max: 1_000_000 }),  // Cents
  currency: fc.constantFrom("USD", "EUR", "GBP"),
});

it("discount should never result in negative price", () => {
  fc.assert(
    fc.property(
      moneyArbitrary,
      fc.integer({ min: 0, max: 100 }),  // Discount percentage
      (price, discountPercent) => {
        const discounted = applyDiscount(price, discountPercent);
        expect(discounted.amount).toBeGreaterThanOrEqual(0);
      }
    )
  );
});

it("total should equal sum of line items", () => {
  fc.assert(
    fc.property(
      fc.array(moneyArbitrary, { minLength: 1, maxLength: 50 }),
      (items) => {
        const total = calculateTotal(items);
        const expected = items.reduce((sum, item) => sum + item.amount, 0);
        expect(total).toBe(expected);
      }
    )
  );
});

Shrinking (Automatic Minimal Reproduction)

// When a property fails, fast-check automatically finds the SMALLEST failing input

it("handles edge cases in URL parsing", () => {
  fc.assert(
    fc.property(fc.webUrl(), (url) => {
      const parsed = parseUrl(url);
      expect(parsed.protocol).toBeTruthy();
      // If this fails on a complex URL, fast-check shrinks it to
      // the simplest URL that still fails, e.g., "http://a"
    })
  );
});

Examples

Example 1: Test a parser for edge cases

User prompt: "My CSV parser breaks on weird inputs. Find all the edge cases."

The agent will write properties like "parse(serialize(data)) === data", generate random CSV data with edge cases (commas in fields, newlines, empty cells, Unicode), and identify failing inputs.

Example 2: Verify pricing logic

User prompt: "Test our discount calculation to make sure it never produces negative prices or rounding errors."

The agent will generate random prices, discount percentages, and coupon combinations, then verify invariants (non-negative, correct rounding, order doesn't matter).

Guidelines

  • Think in properties, not examples — "sorted output is ordered" not "sort([3,1,2]) = [1,2,3]"
  • Roundtrip is the easiest propertydecode(encode(x)) === x
  • fc.assert runs 100 iterations by default — increase with { numRuns: 1000 }
  • Shrinking is automatic — failed inputs are minimized to the simplest case
  • Built-in arbitraries cover most needsstring, integer, array, record, date, uuid, emailAddress
  • constantFrom for enumsfc.constantFrom("a", "b", "c")
  • fc.pre(condition) for preconditions — skip inputs that don't meet criteria
  • Combine with example-based tests — properties find unknowns, examples verify knowns
  • Seed for reproducibility — failed runs print a seed; re-run with same seed to reproduce