{
  "schemaVersion": "1.0",
  "item": {
    "slug": "testing-patterns",
    "name": "Testing Patterns",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/wpank/testing-patterns",
    "canonicalUrl": "https://clawhub.ai/wpank/testing-patterns",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/testing-patterns",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=testing-patterns",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "README.md",
      "SKILL.md",
      "templates/platforms/claude-knowledge.md",
      "templates/platforms/copilot-instructions.md",
      "templates/platforms/cursorrules.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-05-07T17:22:31.273Z",
      "expiresAt": "2026-05-14T17:22:31.273Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=afrexai-annual-report",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=afrexai-annual-report",
        "contentDisposition": "attachment; filename=\"afrexai-annual-report-1.0.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/testing-patterns"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/testing-patterns",
    "agentPageUrl": "https://openagent3.xyz/skills/testing-patterns/agent",
    "manifestUrl": "https://openagent3.xyz/skills/testing-patterns/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/testing-patterns/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Testing Patterns",
        "body": "Write tests that catch bugs, not tests that pass. — Confidence through coverage, speed through isolation."
      },
      {
        "title": "Testing Pyramid",
        "body": "LevelRatioSpeedCostConfidenceScopeUnit~70%msLowLow (isolated)Single function/classIntegration~20%secondsMediumMediumModule boundaries, APIs, DBE2E~10%minutesHighHigh (realistic)Full user workflows\n\nRule: If your E2E tests outnumber your unit tests, invert the pyramid."
      },
      {
        "title": "Core Patterns",
        "body": "PatternWhen to UseStructureArrange-Act-AssertDefault for all unit testsSetup, Execute, VerifyGiven-When-ThenBDD-style, behavior-focusedPrecondition, Action, OutcomeParameterizedSame logic, multiple inputsData-driven test casesSnapshotUI components, serialized outputCompare against saved baselineProperty-BasedMathematical invariantsGenerate random inputs, assert properties"
      },
      {
        "title": "Arrange-Act-Assert (AAA)",
        "body": "The default structure for every unit test. Clear separation of setup, execution, and verification makes tests readable and maintainable.\n\n// Clean AAA structure\ntest('calculates order total with tax', () => {\n  // Arrange\n  const items = [{ price: 10, qty: 2 }, { price: 5, qty: 1 }];\n  const taxRate = 0.08;\n\n  // Act\n  const total = calculateTotal(items, taxRate);\n\n  // Assert\n  expect(total).toBe(27.0);\n});"
      },
      {
        "title": "Test Doubles",
        "body": "Use the right type of test double for the situation. Each serves a different purpose.\n\nDoublePurposeWhen to UseExampleStubReturns canned dataControl indirect inputjest.fn().mockReturnValue(42)MockVerifies interactionsAssert something was calledexpect(mock).toHaveBeenCalledWith('arg')SpyWraps real implementationObserve without replacingjest.spyOn(service, 'save')FakeWorking simplified implNeed realistic behaviorIn-memory database, fake HTTP server\n\n// Stub — control indirect input\nconst getUser = jest.fn().mockResolvedValue({ id: 1, name: 'Alice' });\n\n// Spy — observe without replacing\nconst spy = jest.spyOn(logger, 'warn');\nprocessInvalidInput(data);\nexpect(spy).toHaveBeenCalledWith('Invalid input received');\n\n// Fake — lightweight substitute\nclass FakeUserRepo implements UserRepository {\n  private users = new Map<string, User>();\n  async save(user: User) { this.users.set(user.id, user); }\n  async findById(id: string) { return this.users.get(id) ?? null; }\n}"
      },
      {
        "title": "Parameterized Tests",
        "body": "Use parameterized tests when the same logic needs verification with multiple inputs. This eliminates copy-paste tests while providing comprehensive coverage.\n\n// Vitest/Jest\ntest.each([\n  ['hello', 'HELLO'],\n  ['world', 'WORLD'],\n  ['', ''],\n  ['123abc', '123ABC'],\n])('toUpperCase(%s) returns %s', (input, expected) => {\n  expect(input.toUpperCase()).toBe(expected);\n});\n\n# pytest\n@pytest.mark.parametrize(\"input,expected\", [\n    (\"hello\", \"HELLO\"),\n    (\"world\", \"WORLD\"),\n    (\"\", \"\"),\n])\ndef test_to_upper(input, expected):\n    assert input.upper() == expected\n\n// Go — table-driven tests (idiomatic)\nfunc TestAdd(t *testing.T) {\n    tests := []struct {\n        name     string\n        a, b     int\n        expected int\n    }{\n        {\"positive\", 2, 3, 5},\n        {\"zero\", 0, 0, 0},\n        {\"negative\", -1, -2, -3},\n    }\n    for _, tc := range tests {\n        t.Run(tc.name, func(t *testing.T) {\n            if got := Add(tc.a, tc.b); got != tc.expected {\n                t.Errorf(\"Add(%d,%d) = %d, want %d\", tc.a, tc.b, got, tc.expected)\n            }\n        })\n    }\n}"
      },
      {
        "title": "Database Testing Strategies",
        "body": "StrategyApproachTrade-offTransaction rollbackWrap each test in a transaction, rollback afterFast, but hides commit bugsFixtures/seedsLoad known data before suitePredictable, but brittle if schema changesFactory functionsGenerate data programmaticallyFlexible, but more setup codeTestcontainersSpin up real DB in DockerRealistic, but slower startup\n\n// Transaction rollback pattern (Prisma)\nbeforeEach(async () => {\n  await prisma.$executeRaw`BEGIN`;\n});\nafterEach(async () => {\n  await prisma.$executeRaw`ROLLBACK`;\n});\n\ntest('creates user in database', async () => {\n  const user = await createUser({ name: 'Alice', email: 'a@b.com' });\n  const found = await prisma.user.findUnique({ where: { id: user.id } });\n  expect(found?.name).toBe('Alice');\n});"
      },
      {
        "title": "API Testing",
        "body": "// Supertest (Node.js)\nimport request from 'supertest';\nimport { app } from '../src/app';\n\ndescribe('POST /api/users', () => {\n  it('creates a user and returns 201', async () => {\n    const res = await request(app)\n      .post('/api/users')\n      .send({ name: 'Alice', email: 'alice@test.com' })\n      .expect(201);\n\n    expect(res.body).toMatchObject({\n      id: expect.any(String),\n      name: 'Alice',\n    });\n  });\n\n  it('returns 400 for invalid email', async () => {\n    await request(app)\n      .post('/api/users')\n      .send({ name: 'Alice', email: 'not-an-email' })\n      .expect(400);\n  });\n});"
      },
      {
        "title": "Mock Boundaries, Not Implementations",
        "body": "The fundamental rule: mock at system boundaries (external APIs, databases, file systems) and never mock internal domain logic.\n\n// BAD — mocking internal implementation\njest.mock('./utils/formatDate');  // Breaks on refactor\n\n// GOOD — mocking external boundary\njest.mock('./services/paymentGateway');  // Third-party API is the boundary"
      },
      {
        "title": "When to Mock vs Not Mock",
        "body": "MockDon't MockHTTP APIs, external servicesPure functionsDatabase (in unit tests)Your own domain logicFile system, networkData transformationsTime/Date (Date.now)Simple calculationsEnvironment variablesInternal class methods"
      },
      {
        "title": "Dependency Injection for Testability",
        "body": "Structure code so dependencies can be swapped in tests. This is the single most impactful pattern for testable code.\n\n// Injectable dependencies — easy to test\nclass OrderService {\n  constructor(\n    private paymentGateway: PaymentGateway,\n    private inventory: InventoryService,\n    private notifier: NotificationService,\n  ) {}\n\n  async placeOrder(order: Order): Promise<OrderResult> {\n    const stock = await this.inventory.check(order.items);\n    if (!stock.available) return { status: 'out_of_stock' };\n\n    const payment = await this.paymentGateway.charge(order.total);\n    if (!payment.success) return { status: 'payment_failed' };\n\n    await this.notifier.send(order.userId, 'Order confirmed');\n    return { status: 'confirmed', id: payment.transactionId };\n  }\n}\n\n// In tests — inject fakes\nconst service = new OrderService(\n  new FakePaymentGateway(),\n  new FakeInventory({ available: true }),\n  new FakeNotifier(),\n);"
      },
      {
        "title": "Framework Quick Reference",
        "body": "FrameworkLanguageTypeTest RunnerAssertionJestJS/TSUnit/IntegrationBuilt-inexpect()VitestJS/TSUnit/IntegrationVite-nativeexpect() (Jest-compatible)PlaywrightJS/TS/PythonE2EBuilt-inexpect() / locatorsCypressJS/TSE2EBuilt-incy.should()pytestPythonUnit/IntegrationBuilt-inassertGo testingGoUnit/Integrationgo testt.Error() / testifyRustRustUnit/Integrationcargo testassert!() / assert_eq!()JUnit 5Java/KotlinUnit/IntegrationBuilt-inassertEquals()RSpecRubyUnit/IntegrationBuilt-inexpect().toPHPUnitPHPUnit/IntegrationBuilt-in$this->assert*()xUnitC#Unit/IntegrationBuilt-inAssert.Equal()"
      },
      {
        "title": "Test Quality Checklist",
        "body": "QualityRuleWhyDeterministicSame input produces same result, every timeFlaky tests erode trustIsolatedNo shared mutable state between testsOrder-dependent tests break in CIFastUnit: < 10ms, Integration: < 1s, E2E: < 30sSlow tests don't get runReadableTest name describes the scenario and expectationTests are documentationMaintainableChange one behavior, change one testBrittle tests slow developmentFocusedOne logical assertion per testFailures pinpoint the problem\n\nNaming convention: test_[unit]_[scenario]_[expected result] or should [do X] when [condition Y]"
      },
      {
        "title": "When to Aim for What",
        "body": "TargetWhenRationale80%+ line coverageBusiness logic, utilities, core domainHigh ROI — catches most regressions90%+ branch coveragePayment processing, auth, security-criticalEdge cases matter here100% coverageAlmost never — diminishing returnsGetter/setter tests add noise, not confidenceMutation testingCritical paths after coverage is highVerifies tests actually catch bugs"
      },
      {
        "title": "What NOT to Test",
        "body": "SkipReasonGenerated code (Prisma client, protobuf)Maintained by toolingThird-party library internalsNot your responsibilitySimple getters/settersNo logic to verifyConfiguration filesTest the behavior they configure insteadConsole.log / print statementsSide effects with no business value"
      },
      {
        "title": "Test Organization",
        "body": "src/\n├── services/\n│   ├── order.service.ts\n│   └── order.service.test.ts      # Co-located unit tests\n├── api/\n│   └── routes/\n│       └── orders.ts\ntests/\n├── integration/\n│   ├── api/\n│   │   └── orders.test.ts         # API integration tests\n│   └── db/\n│       └── order.repo.test.ts     # DB integration tests\n├── e2e/\n│   ├── pages/                     # Page objects\n│   │   └── checkout.page.ts\n│   └── specs/\n│       └── checkout.spec.ts       # E2E specs\n└── helpers/\n    ├── factories.ts               # Test data factories\n    └── setup.ts                   # Global test setup\n\nRule: Co-locate unit tests with source. Separate integration and E2E tests into dedicated directories."
      },
      {
        "title": "Anti-Patterns",
        "body": "Anti-PatternProblemFixTesting implementationTests break on refactor, not on bugsTest behavior and outputs, not internalsFlaky testsNon-deterministic failures erode CI trustRemove time/order/network dependenciesTest pollutionShared mutable state leaks between testsReset state in beforeEach / setUpSleeping in testssleep(2000) is slow and unreliableUse explicit waits, polling, or eventsGiant arrange50 lines of setup obscure intentExtract factories/builders/fixturesAssert-free testsTest runs but verifies nothingEvery test must assert or expectOvermockingMocking everything tests nothing realOnly mock external boundariesCopy-paste testsDuplicated tests diverge and rotUse parameterized tests or helpersTesting the frameworkVerifying library code worksTest your logic, trust dependenciesIgnoring test failuresskip, xit, @Disabled accumulateFix or delete — never hoard skipped testsTight coupling to DBTests fail when schema changesUse repository pattern + fakes for unit testsOne giant testSingle test covers 10 scenariosSplit into focused, named testsNo test for bug fixRegression reappears laterEvery bug fix gets a regression test"
      },
      {
        "title": "NEVER Do",
        "body": "NEVER test implementation details instead of behavior — tests must verify what the code does, not how it does it\nNEVER use sleep() in tests — use explicit waits, polling, events, or assertions that auto-retry\nNEVER share mutable state between tests — each test sets up and tears down its own state\nNEVER write assert-free tests — a test that asserts nothing proves nothing\nNEVER mock internal domain logic — only mock at system boundaries (network, DB, filesystem, clock)\nNEVER skip tests without a linked issue and a plan to re-enable — skipped tests rot into permanent gaps\nNEVER leave a test suite in a failing state — fix it or remove it with justification before moving on\nNEVER chase 100% coverage as a goal — coverage percentage is a tool, not a target; strong assertions on critical paths beat weak assertions everywhere"
      },
      {
        "title": "Summary",
        "body": "DoDon'tTest behavior, not implementationMock everything in sightWrite the test before fixing a bugSkip tests to ship fasterKeep tests fast and deterministicUse sleep() or shared stateUse factories for test dataCopy-paste setup across testsMock at system boundariesMock internal functionsName tests descriptivelyName tests test1, test2Run tests in CI on every pushOnly run tests locallyDelete or fix skipped testsLet @skip accumulate foreverUse parameterized tests for variantsDuplicate test codeInject dependencies for testabilityHard-code dependencies\n\nRemember: Tests are a safety net — a fast, trustworthy suite lets you refactor fearlessly and ship with confidence."
      }
    ],
    "body": "Testing Patterns\n\nWrite tests that catch bugs, not tests that pass. — Confidence through coverage, speed through isolation.\n\nTesting Pyramid\nLevel\tRatio\tSpeed\tCost\tConfidence\tScope\nUnit\t~70%\tms\tLow\tLow (isolated)\tSingle function/class\nIntegration\t~20%\tseconds\tMedium\tMedium\tModule boundaries, APIs, DB\nE2E\t~10%\tminutes\tHigh\tHigh (realistic)\tFull user workflows\n\nRule: If your E2E tests outnumber your unit tests, invert the pyramid.\n\nUnit Testing Patterns\nCore Patterns\nPattern\tWhen to Use\tStructure\nArrange-Act-Assert\tDefault for all unit tests\tSetup, Execute, Verify\nGiven-When-Then\tBDD-style, behavior-focused\tPrecondition, Action, Outcome\nParameterized\tSame logic, multiple inputs\tData-driven test cases\nSnapshot\tUI components, serialized output\tCompare against saved baseline\nProperty-Based\tMathematical invariants\tGenerate random inputs, assert properties\nArrange-Act-Assert (AAA)\n\nThe default structure for every unit test. Clear separation of setup, execution, and verification makes tests readable and maintainable.\n\n// Clean AAA structure\ntest('calculates order total with tax', () => {\n  // Arrange\n  const items = [{ price: 10, qty: 2 }, { price: 5, qty: 1 }];\n  const taxRate = 0.08;\n\n  // Act\n  const total = calculateTotal(items, taxRate);\n\n  // Assert\n  expect(total).toBe(27.0);\n});\n\nTest Doubles\n\nUse the right type of test double for the situation. Each serves a different purpose.\n\nDouble\tPurpose\tWhen to Use\tExample\nStub\tReturns canned data\tControl indirect input\tjest.fn().mockReturnValue(42)\nMock\tVerifies interactions\tAssert something was called\texpect(mock).toHaveBeenCalledWith('arg')\nSpy\tWraps real implementation\tObserve without replacing\tjest.spyOn(service, 'save')\nFake\tWorking simplified impl\tNeed realistic behavior\tIn-memory database, fake HTTP server\n// Stub — control indirect input\nconst getUser = jest.fn().mockResolvedValue({ id: 1, name: 'Alice' });\n\n// Spy — observe without replacing\nconst spy = jest.spyOn(logger, 'warn');\nprocessInvalidInput(data);\nexpect(spy).toHaveBeenCalledWith('Invalid input received');\n\n// Fake — lightweight substitute\nclass FakeUserRepo implements UserRepository {\n  private users = new Map<string, User>();\n  async save(user: User) { this.users.set(user.id, user); }\n  async findById(id: string) { return this.users.get(id) ?? null; }\n}\n\nParameterized Tests\n\nUse parameterized tests when the same logic needs verification with multiple inputs. This eliminates copy-paste tests while providing comprehensive coverage.\n\n// Vitest/Jest\ntest.each([\n  ['hello', 'HELLO'],\n  ['world', 'WORLD'],\n  ['', ''],\n  ['123abc', '123ABC'],\n])('toUpperCase(%s) returns %s', (input, expected) => {\n  expect(input.toUpperCase()).toBe(expected);\n});\n\n# pytest\n@pytest.mark.parametrize(\"input,expected\", [\n    (\"hello\", \"HELLO\"),\n    (\"world\", \"WORLD\"),\n    (\"\", \"\"),\n])\ndef test_to_upper(input, expected):\n    assert input.upper() == expected\n\n// Go — table-driven tests (idiomatic)\nfunc TestAdd(t *testing.T) {\n    tests := []struct {\n        name     string\n        a, b     int\n        expected int\n    }{\n        {\"positive\", 2, 3, 5},\n        {\"zero\", 0, 0, 0},\n        {\"negative\", -1, -2, -3},\n    }\n    for _, tc := range tests {\n        t.Run(tc.name, func(t *testing.T) {\n            if got := Add(tc.a, tc.b); got != tc.expected {\n                t.Errorf(\"Add(%d,%d) = %d, want %d\", tc.a, tc.b, got, tc.expected)\n            }\n        })\n    }\n}\n\nIntegration Testing Patterns\nDatabase Testing Strategies\nStrategy\tApproach\tTrade-off\nTransaction rollback\tWrap each test in a transaction, rollback after\tFast, but hides commit bugs\nFixtures/seeds\tLoad known data before suite\tPredictable, but brittle if schema changes\nFactory functions\tGenerate data programmatically\tFlexible, but more setup code\nTestcontainers\tSpin up real DB in Docker\tRealistic, but slower startup\n// Transaction rollback pattern (Prisma)\nbeforeEach(async () => {\n  await prisma.$executeRaw`BEGIN`;\n});\nafterEach(async () => {\n  await prisma.$executeRaw`ROLLBACK`;\n});\n\ntest('creates user in database', async () => {\n  const user = await createUser({ name: 'Alice', email: 'a@b.com' });\n  const found = await prisma.user.findUnique({ where: { id: user.id } });\n  expect(found?.name).toBe('Alice');\n});\n\nAPI Testing\n// Supertest (Node.js)\nimport request from 'supertest';\nimport { app } from '../src/app';\n\ndescribe('POST /api/users', () => {\n  it('creates a user and returns 201', async () => {\n    const res = await request(app)\n      .post('/api/users')\n      .send({ name: 'Alice', email: 'alice@test.com' })\n      .expect(201);\n\n    expect(res.body).toMatchObject({\n      id: expect.any(String),\n      name: 'Alice',\n    });\n  });\n\n  it('returns 400 for invalid email', async () => {\n    await request(app)\n      .post('/api/users')\n      .send({ name: 'Alice', email: 'not-an-email' })\n      .expect(400);\n  });\n});\n\nMocking Best Practices\nMock Boundaries, Not Implementations\n\nThe fundamental rule: mock at system boundaries (external APIs, databases, file systems) and never mock internal domain logic.\n\n// BAD — mocking internal implementation\njest.mock('./utils/formatDate');  // Breaks on refactor\n\n// GOOD — mocking external boundary\njest.mock('./services/paymentGateway');  // Third-party API is the boundary\n\nWhen to Mock vs Not Mock\nMock\tDon't Mock\nHTTP APIs, external services\tPure functions\nDatabase (in unit tests)\tYour own domain logic\nFile system, network\tData transformations\nTime/Date (Date.now)\tSimple calculations\nEnvironment variables\tInternal class methods\nDependency Injection for Testability\n\nStructure code so dependencies can be swapped in tests. This is the single most impactful pattern for testable code.\n\n// Injectable dependencies — easy to test\nclass OrderService {\n  constructor(\n    private paymentGateway: PaymentGateway,\n    private inventory: InventoryService,\n    private notifier: NotificationService,\n  ) {}\n\n  async placeOrder(order: Order): Promise<OrderResult> {\n    const stock = await this.inventory.check(order.items);\n    if (!stock.available) return { status: 'out_of_stock' };\n\n    const payment = await this.paymentGateway.charge(order.total);\n    if (!payment.success) return { status: 'payment_failed' };\n\n    await this.notifier.send(order.userId, 'Order confirmed');\n    return { status: 'confirmed', id: payment.transactionId };\n  }\n}\n\n// In tests — inject fakes\nconst service = new OrderService(\n  new FakePaymentGateway(),\n  new FakeInventory({ available: true }),\n  new FakeNotifier(),\n);\n\nFramework Quick Reference\nFramework\tLanguage\tType\tTest Runner\tAssertion\nJest\tJS/TS\tUnit/Integration\tBuilt-in\texpect()\nVitest\tJS/TS\tUnit/Integration\tVite-native\texpect() (Jest-compatible)\nPlaywright\tJS/TS/Python\tE2E\tBuilt-in\texpect() / locators\nCypress\tJS/TS\tE2E\tBuilt-in\tcy.should()\npytest\tPython\tUnit/Integration\tBuilt-in\tassert\nGo testing\tGo\tUnit/Integration\tgo test\tt.Error() / testify\nRust\tRust\tUnit/Integration\tcargo test\tassert!() / assert_eq!()\nJUnit 5\tJava/Kotlin\tUnit/Integration\tBuilt-in\tassertEquals()\nRSpec\tRuby\tUnit/Integration\tBuilt-in\texpect().to\nPHPUnit\tPHP\tUnit/Integration\tBuilt-in\t$this->assert*()\nxUnit\tC#\tUnit/Integration\tBuilt-in\tAssert.Equal()\nTest Quality Checklist\nQuality\tRule\tWhy\nDeterministic\tSame input produces same result, every time\tFlaky tests erode trust\nIsolated\tNo shared mutable state between tests\tOrder-dependent tests break in CI\nFast\tUnit: < 10ms, Integration: < 1s, E2E: < 30s\tSlow tests don't get run\nReadable\tTest name describes the scenario and expectation\tTests are documentation\nMaintainable\tChange one behavior, change one test\tBrittle tests slow development\nFocused\tOne logical assertion per test\tFailures pinpoint the problem\n\nNaming convention: test_[unit]_[scenario]_[expected result] or should [do X] when [condition Y]\n\nCoverage Strategy\nWhen to Aim for What\nTarget\tWhen\tRationale\n80%+ line coverage\tBusiness logic, utilities, core domain\tHigh ROI — catches most regressions\n90%+ branch coverage\tPayment processing, auth, security-critical\tEdge cases matter here\n100% coverage\tAlmost never — diminishing returns\tGetter/setter tests add noise, not confidence\nMutation testing\tCritical paths after coverage is high\tVerifies tests actually catch bugs\nWhat NOT to Test\nSkip\tReason\nGenerated code (Prisma client, protobuf)\tMaintained by tooling\nThird-party library internals\tNot your responsibility\nSimple getters/setters\tNo logic to verify\nConfiguration files\tTest the behavior they configure instead\nConsole.log / print statements\tSide effects with no business value\nTest Organization\nsrc/\n├── services/\n│   ├── order.service.ts\n│   └── order.service.test.ts      # Co-located unit tests\n├── api/\n│   └── routes/\n│       └── orders.ts\ntests/\n├── integration/\n│   ├── api/\n│   │   └── orders.test.ts         # API integration tests\n│   └── db/\n│       └── order.repo.test.ts     # DB integration tests\n├── e2e/\n│   ├── pages/                     # Page objects\n│   │   └── checkout.page.ts\n│   └── specs/\n│       └── checkout.spec.ts       # E2E specs\n└── helpers/\n    ├── factories.ts               # Test data factories\n    └── setup.ts                   # Global test setup\n\n\nRule: Co-locate unit tests with source. Separate integration and E2E tests into dedicated directories.\n\nAnti-Patterns\nAnti-Pattern\tProblem\tFix\nTesting implementation\tTests break on refactor, not on bugs\tTest behavior and outputs, not internals\nFlaky tests\tNon-deterministic failures erode CI trust\tRemove time/order/network dependencies\nTest pollution\tShared mutable state leaks between tests\tReset state in beforeEach / setUp\nSleeping in tests\tsleep(2000) is slow and unreliable\tUse explicit waits, polling, or events\nGiant arrange\t50 lines of setup obscure intent\tExtract factories/builders/fixtures\nAssert-free tests\tTest runs but verifies nothing\tEvery test must assert or expect\nOvermocking\tMocking everything tests nothing real\tOnly mock external boundaries\nCopy-paste tests\tDuplicated tests diverge and rot\tUse parameterized tests or helpers\nTesting the framework\tVerifying library code works\tTest your logic, trust dependencies\nIgnoring test failures\tskip, xit, @Disabled accumulate\tFix or delete — never hoard skipped tests\nTight coupling to DB\tTests fail when schema changes\tUse repository pattern + fakes for unit tests\nOne giant test\tSingle test covers 10 scenarios\tSplit into focused, named tests\nNo test for bug fix\tRegression reappears later\tEvery bug fix gets a regression test\nNEVER Do\nNEVER test implementation details instead of behavior — tests must verify what the code does, not how it does it\nNEVER use sleep() in tests — use explicit waits, polling, events, or assertions that auto-retry\nNEVER share mutable state between tests — each test sets up and tears down its own state\nNEVER write assert-free tests — a test that asserts nothing proves nothing\nNEVER mock internal domain logic — only mock at system boundaries (network, DB, filesystem, clock)\nNEVER skip tests without a linked issue and a plan to re-enable — skipped tests rot into permanent gaps\nNEVER leave a test suite in a failing state — fix it or remove it with justification before moving on\nNEVER chase 100% coverage as a goal — coverage percentage is a tool, not a target; strong assertions on critical paths beat weak assertions everywhere\nSummary\nDo\tDon't\nTest behavior, not implementation\tMock everything in sight\nWrite the test before fixing a bug\tSkip tests to ship faster\nKeep tests fast and deterministic\tUse sleep() or shared state\nUse factories for test data\tCopy-paste setup across tests\nMock at system boundaries\tMock internal functions\nName tests descriptively\tName tests test1, test2\nRun tests in CI on every push\tOnly run tests locally\nDelete or fix skipped tests\tLet @skip accumulate forever\nUse parameterized tests for variants\tDuplicate test code\nInject dependencies for testability\tHard-code dependencies\n\nRemember: Tests are a safety net — a fast, trustworthy suite lets you refactor fearlessly and ship with confidence."
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/wpank/testing-patterns",
    "publisherUrl": "https://clawhub.ai/wpank/testing-patterns",
    "owner": "wpank",
    "version": "0.1.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/testing-patterns",
    "downloadUrl": "https://openagent3.xyz/downloads/testing-patterns",
    "agentUrl": "https://openagent3.xyz/skills/testing-patterns/agent",
    "manifestUrl": "https://openagent3.xyz/skills/testing-patterns/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/testing-patterns/agent.md"
  }
}