Token导航 LogoToken导航

Agent Skill · 研究检索

effect-testing(效果测试)

用于辅助测试设计、自动化测试、用例整理和回归验证。它适合让 Agent 编写单元测试、端到端测试、测试计划或根据失败日志定位问题。使用时需要确认项目测试框架、运行命令和夹具数据,避免为了通过测试而改坏真实逻辑;涉及浏览器或外部服务时,应区分本地模拟、测试环境和生产环境。

effect-testing 是研究检索类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为需要联网;许可证为 MIT,第三方扫描有未通过项,按安装量在研究检索类的 73,675 个 Skill 里排第 46,976。

总安装 753周安装 32GitHub Stars 142下载 264核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
MIT

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:effect-testing(效果测试)
来源仓库:https://github.com/thebushidocollective/han
仓库路径:skills/effect-testing
安装命令:
npx skills add https://github.com/thebushidocollective/han --skill effect-testing
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/thebushidocollective/han --skill effect-testing

这个 Skill 是做什么的

研究检索类 Skill 主要解决「找资料、核对事实、把来源整理清楚」的问题,通常会让助手先检索再总结。

用于辅助测试设计、自动化测试、用例整理和回归验证。它适合让 Agent 编写单元测试、端到端测试、测试计划或根据失败日志定位问题。使用时需要确认项目测试框架、运行命令和夹具数据,避免为了通过测试而改坏真实逻辑。涉及浏览器或外部服务时,应区分本地模拟、测试环境和生产环境。

通过 npx skills add 命令从指定 GitHub 路径安装并使用。

来源仓库内路径:skills/effect-testing

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/thebushidocollective/han --skill effect-testin…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要需要联网,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

effect-testing 怎么安装?

在终端执行 npx skills add https://github.com/thebushidocollective/han --skill effect-testing。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

effect-testing 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

effect-testing 需要什么权限?

权限级别是需要联网。该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

effect-testing 是免费的吗?

来源标注的许可证是 MIT。本站不代收任何费用,也不托管安装包;能否商用、要不要署名,以许可证原文为准。

effect-testing 用的人多吗?

公开数据是累计安装 753 次,近一周安装 32 次,下载 264 次,GitHub 142 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

effect-testing 安全吗?

第三方扫描有未通过项,风险较高。除非你确认过源码,否则不建议直接安装到常用环境。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 3 个目录同时收录,说明这个 Skill 流传比较广。
  • 许可证明确为 MIT,商用和分发边界好判断。

先想清楚的地方

  • 第三方扫描存在提醒项或未通过项,需要人工逐条确认。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理研究检索类任务、又不想每次都手写提示词的人。

不太适合

  • 需要厂商级技术支持和 SLA 的生产系统。

研究检索类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
find-skills

寻找技能 · Codex、Claude

31,199,81316,486操作浏览器MIT有提醒
self-improving-agent

自我改进 Agent · OpenClaw

16,464,0023,396接触敏感数据MIT-0通过
soultrace

灵魂追踪 · Codex、Claude

7,588,94412需要联网未明确有提醒
self-improving

自我完善 · OpenClaw

6,829,2841,046需要联网MIT-0通过
microsoft-foundry

微软代工厂 · Codex、Claude

6,614,144764调用外部服务未明确有提醒
effect-testing

效果测试 · 本页

753142需要联网MIT未通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

Effect Testing

Master testing Effect applications with test utilities, mock layers, and patterns for testing effectful code. This skill covers unit testing, integration testing, and testing concurrent and resource-managed code.

Basic Effect Testing

Testing with Effect.gen

import { Effect } from "effect"
import { describe, it, expect } from "vitest"

describe("User Service", () => {
  it("should fetch user by ID", async () => {
    const program = Effect.gen(function* () {
      const user = yield* fetchUser("123")
      return user
    })

    const result = await Effect.runPromise(program.pipe(
      Effect.provide(TestLayer)
    ))

    expect(result.id).toBe("123")
    expect(result.name).toBe("Alice")
  })
})

Testing Success and Failure

import { Effect, Exit } from "effect"
import { describe, it, expect } from "vitest"

describe("Validation", () => {
  it("should succeed with valid email", async () => {
    const program = validateEmail("alice@example.com")

    const result = await Effect.runPromise(program)

    expect(result).toBe("alice@example.com")
  })

  it("should fail with invalid email", async () => {
    const program = validateEmail("invalid")

    const exit = await Effect.runPromiseExit(program)

    expect(Exit.isFailure(exit)).toBe(true)

    if (Exit.isFailure(exit)) {
      const error = Cause.failureOption(exit.cause)
      expect(error._tag).toBe("ValidationError")
    }
  })
})

Mock Layers for Testing

Creating Test Layers

import { Context, Effect, Layer } from "effect"

interface UserRepository {
  findById: (id: string) => Effect.Effect<Option<User>, DbError, never>
  save: (user: User) => Effect.Effect<User, DbError, never>
}

const UserRepository = Context.GenericTag<UserRepository>("UserRepository")

// In-memory test implementation
const UserRepositoryTest = Layer.succeed(
  UserRepository,
  {
    findById: (id: string) =>
      Effect.succeed(
        id === "1"
          ? Option.some({ id: "1", name: "Alice", email: "alice@example.com" })
          : Option.none()
      ),

    save: (user: User) =>
      Effect.succeed(user)
  }
)

// Use in tests
const testProgram = Effect.gen(function* () {
  const repo = yield* UserRepository
  const user = yield* repo.findById("1")
  return user
}).pipe(
  Effect.provide(UserRepositoryTest)
)

Stateful Mock Layers

import { Context, Effect, Layer, Ref } from "effect"

// Mock with state
const UserRepositoryStateful = Layer.effect(
  UserRepository,
  Effect.gen(function* () {
    const storage = yield* Ref.make<Map<string, User>>(new Map([
      ["1", { id: "1", name: "Alice", email: "alice@example.com" }]
    ]))

    return {
      findById: (id: string) =>
        storage.get.pipe(
          Effect.map((map) => {
            const user = map.get(id)
            return user ? Option.some(user) : Option.none()
          })
        ),

      save: (user: User) =>
        storage.update((map) => map.set(user.id, user)).pipe(
          Effect.map(() => user)
        )
    }
  })
)

// Test with state
describe("User Repository", () => {
  it("should save and retrieve user", async () => {
    const program = Effect.gen(function* () {
      const repo = yield* UserRepository

      const newUser = { id: "2", name: "Bob", email: "bob@example.com" }
      yield* repo.save(newUser)

      const retrieved = yield* repo.findById("2")
      return retrieved
    }).pipe(
      Effect.provide(UserRepositoryStateful)
    )

    const result = await Effect.runPromise(program)

    expect(Option.isSome(result)).toBe(true)
    if (Option.isSome(result)) {
      expect(result.value.name).toBe("Bob")
    }
  })
})

Spy Layers

Recording Calls

import { Context, Effect, Layer, Ref } from "effect"

interface LoggerCalls {
  info: string[]
  error: string[]
}

const LoggerSpy = Layer.effect(
  Logger,
  Effect.gen(function* () {
    const calls = yield* Ref.make<LoggerCalls>({
      info: [],
      error: []
    })

    return {
      logger: {
        info: (message: string) =>
          calls.update((c) => ({
            ...c,
            info: [...c.info, message]
          })),

        error: (message: string) =>
          calls.update((c) => ({
            ...c,
            error: [...c.error, message]
          }))
      },

      getCalls: () => calls.get
    }
  })
)

// Test with spy
describe("User Service", () => {
  it("should log user creation", async () => {
    const program = Effect.gen(function* () {
      const spy = yield* LoggerSpy
      const service = yield* UserService

      yield* service.createUser({ name: "Alice" })

      const calls = yield* spy.getCalls()
      return calls
    }).pipe(
      Effect.provide(Layer.merge(LoggerSpy, UserServiceLive))
    )

    const calls = await Effect.runPromise(program)

    expect(calls.info).toContain("Creating user: Alice")
  })
})

Testing Error Scenarios

Testing Expected Errors

import { Effect } from "effect"
import { describe, it, expect } from "vitest"

describe("Error Handling", () => {
  it("should handle NotFoundError", async () => {
    const program = Effect.gen(function* () {
      const result = yield* fetchUser("999").pipe(
        Effect.catchTag("NotFoundError", (error) =>
          Effect.succeed({ id: "default", name: "Guest" })
        )
      )
      return result
    })

    const result = await Effect.runPromise(program.pipe(
      Effect.provide(TestLayer)
    ))

    expect(result.name).toBe("Guest")
  })

  it("should propagate unhandled errors", async () => {
    const program = Effect.gen(function* () {
      const result = yield* fetchUser("999")
      return result
    })

    await expect(
      Effect.runPromise(program.pipe(
        Effect.provide(TestLayer)
      ))
    ).rejects.toThrow()
  })
})

Testing Error Recovery

import { Effect } from "effect"
import { describe, it, expect } from "vitest"

describe("Retry Logic", () => {
  it("should retry on network error", async () => {
    let attempts = 0

    const unstableOperation = Effect.gen(function* () {
      attempts++
      if (attempts < 3) {
        return yield* Effect.fail({ _tag: "NetworkError" })
      }
      return yield* Effect.succeed("Success")
    })

    const program = unstableOperation.pipe(
      Effect.retry(Schedule.recurs(5))
    )

    const result = await Effect.runPromise(program)

    expect(result).toBe("Success")
    expect(attempts).toBe(3)
  })
})

Testing Concurrent Code

Testing Parallel Execution

import { Effect, Ref } from "effect"
import { describe, it, expect } from "vitest"

describe("Concurrent Operations", () => {
  it("should process items in parallel", async () => {
    const program = Effect.gen(function* () {
      const processed = yield* Ref.make<string[]>([])

      const items = ["a", "b", "c", "d", "e"]

      yield* Effect.all(
        items.map((item) =>
          Effect.gen(function* () {
            yield* Effect.sleep("10 millis")
            yield* processed.update((p) => [...p, item])
          })
        ),
        { concurrency: "unbounded" }
      )

      return yield* processed.get
    })

    const result = await Effect.runPromise(program)

    expect(result).toHaveLength(5)
    expect(result).toContain("a")
    expect(result).toContain("b")
  })
})

Testing Fiber Interruption

import { Effect, Fiber, Ref } from "effect"
import { describe, it, expect } from "vitest"

describe("Interruption", () => {
  it("should interrupt long-running task", async () => {
    const program = Effect.gen(function* () {
      const completed = yield* Ref.make(false)

      const fiber = yield* Effect.fork(
        Effect.gen(function* () {
          yield* Effect.sleep("1 second")
          yield* completed.set(true)
        })
      )

      yield* Effect.sleep("100 millis")
      yield* Fiber.interrupt(fiber)

      return yield* completed.get
    })

    const result = await Effect.runPromise(program)

    expect(result).toBe(false)
  })
})

Testing Resource Management

Testing Cleanup

import { Effect, Ref } from "effect"
import { describe, it, expect } from "vitest"

describe("Resource Management", () => {
  it("should clean up resources on success", async () => {
    const program = Effect.gen(function* () {
      const cleaned = yield* Ref.make(false)

      yield* Effect.scoped(
        Effect.gen(function* () {
          yield* Effect.addFinalizer(() =>
            cleaned.set(true)
          )

          yield* Effect.succeed("done")
        })
      )

      return yield* cleaned.get
    })

    const result = await Effect.runPromise(program)

    expect(result).toBe(true)
  })

  it("should clean up resources on failure", async () => {
    const program = Effect.gen(function* () {
      const cleaned = yield* Ref.make(false)

      const result = yield* Effect.scoped(
        Effect.gen(function* () {
          yield* Effect.addFinalizer(() =>
            cleaned.set(true)
          )

          yield* Effect.fail({ _tag: "TestError" })
        })
      ).pipe(
        Effect.catchAll(() => Effect.succeed("handled"))
      )

      const wasCleanedUp = yield* cleaned.get

      return { result, wasCleanedUp }
    })

    const { result, wasCleanedUp } = await Effect.runPromise(program)

    expect(result).toBe("handled")
    expect(wasCleanedUp).toBe(true)
  })
})

Property-Based Testing

Using fast-check with Effect

import { Effect } from "effect"
import { describe, it } from "vitest"
import * as fc from "fast-check"

describe("Property Tests", () => {
  it("should always succeed for valid emails", () => {
    fc.assert(
      fc.asyncProperty(
        fc.emailAddress(),
        async (email) => {
          const program = validateEmail(email)

          const result = await Effect.runPromise(program)

          expect(result).toBe(email.toLowerCase())
        }
      )
    )
  })

  it("should handle any string input", () => {
    fc.assert(
      fc.asyncProperty(
        fc.string(),
        async (input) => {
          const program = parseJSON(input).pipe(
            Effect.catchAll(() => Effect.succeed(null))
          )

          const result = await Effect.runPromise(program)

          // Should never throw
          expect(result).toBeDefined()
        }
      )
    )
  })
})

Testing Best Practices

Test Organization

import { Effect, Layer } from "effect"
import { describe, it, beforeEach, expect } from "vitest"

describe("User Service", () => {
  // Shared test layer
  const TestLayer = Layer.merge(
    UserRepositoryTest,
    LoggerTest,
    ConfigTest
  )

  describe("createUser", () => {
    it("should create user with valid data", async () => {
      const program = Effect.gen(function* () {
        const service = yield* UserService
        const user = yield* service.createUser({
          name: "Alice",
          email: "alice@example.com"
        })
        return user
      }).pipe(
        Effect.provide(TestLayer)
      )

      const result = await Effect.runPromise(program)

      expect(result.name).toBe("Alice")
    })

    it("should fail with invalid email", async () => {
      const program = Effect.gen(function* () {
        const service = yield* UserService
        const user = yield* service.createUser({
          name: "Bob",
          email: "invalid"
        })
        return user
      }).pipe(
        Effect.provide(TestLayer)
      )

      await expect(Effect.runPromise(program)).rejects.toThrow()
    })
  })
})

Best Practices

  1. Use Test Layers: Create dedicated test implementations for services.
  2. Test Error Paths: Test both success and failure scenarios.
  3. Mock Dependencies: Use layers to inject test dependencies.
  4. Test Concurrency: Verify concurrent behavior with multiple fibers.
  5. Test Cleanup: Ensure resources are cleaned up properly.
  6. Use Property Tests: Test invariants with property-based testing.
  7. Isolate Tests: Each test should be independent.
  8. Test Interruption: Verify correct behavior on interruption.
  9. Use Spies: Track calls to verify behavior.
  10. Test Edge Cases: Cover boundary conditions and error cases.

Common Pitfalls

  1. Not Providing Layers: Forgetting to provide required services.
  2. Shared State: Tests interfering with each other via shared state.
  3. Not Testing Errors: Only testing happy paths.
  4. Missing Cleanup Tests: Not verifying finalizers execute.
  5. Ignoring Concurrency: Not testing concurrent behavior.
  6. Flaky Tests: Race conditions in concurrent tests.
  7. Over-Mocking: Mocking too much, losing integration value.
  8. Not Testing Interruption: Missing interruption scenarios.
  9. Hardcoded Timing: Tests that depend on specific timing.
  10. Missing Exit Checks: Not verifying Exit values properly.

When to Use This Skill

Use effect-testing when you need to:

  • Write unit tests for Effect code
  • Create integration tests with dependencies
  • Test error handling and recovery
  • Verify concurrent behavior
  • Test resource cleanup
  • Mock external services
  • Verify retry logic
  • Test interruption handling
  • Use property-based testing
  • Build reliable test suites

Resources

Official Documentation

Testing Libraries

Related Skills

  • effect-core-patterns - Basic Effect operations
  • effect-dependency-injection - Creating test layers
  • effect-error-handling - Testing error scenarios
  • effect-concurrency - Testing concurrent code
  • effect-resource-management - Testing cleanup

平台分布

OpenCode

27.64%
按下载量换算73

Claude Code

23.64%
按下载量换算62

Codex

18.64%
按下载量换算49

windsurf

11.44%
按下载量换算30

Gemini CLI

7.21%
按下载量换算19

Antigravity

3.71%
按下载量换算10

安全审计

Gen Agent Trust Hub

未通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在提醒或未通过项,安装前请自行复核。

继续浏览同类 Skills