Token导航 LogoToken导航

Agent Skill · 研究检索

fdt-refactor-mock-to-fake(fdt 将模拟重构为假)

fdt-refactor-mock-to-fake 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

fdt-refactor-mock-to-fake 是研究检索类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为执行命令;许可证信息还不明确,第三方扫描已通过,按安装量在研究检索类的 73,674 个 Skill 里排第 69,522。

总安装 218周安装 9GitHub Stars 81下载 71核验 2026-05-01

安装说明

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

安装方式

通过对话安装

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

请帮我安装这个 Agent Skill:fdt-refactor-mock-to-fake(fdt 将模拟重构为假)
来源仓库:https://github.com/dagster-io/erk
仓库路径:skills/fdt-refactor-mock-to-fake
安装命令:
npx skills add https://github.com/dagster-io/erk --skill fdt-refactor-mock-to-fake
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/dagster-io/erk --skill fdt-refactor-mock-to-fake

这个 Skill 是做什么的

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

fdt-refactor-mock-to-fake 将 unittest.mock.patch 重构为注入式假对象,提升测试真实性。适用于移除系统边界模拟、配置预定义行为并验证真实依赖交互逻辑。通过 npx skills add 命令安装,优先寻找覆盖全部 mock 的高层抽象网关。

重构后应运行完整测试套件,确保假对象返回值不影响断言有效性。适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

来源仓库内路径:skills/fdt-refactor-mock-to-fake

上手步骤

4 步
  1. 1

    确认自己的宿主工具

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

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/dagster-io/erk --skill fdt-refactor-mock-to-fa…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

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

  4. 4

    按最小权限试用

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

常见问题

6 条

fdt-refactor-mock-to-fake 怎么安装?

在终端执行 npx skills add https://github.com/dagster-io/erk --skill fdt-refactor-mock-to-fake。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

fdt-refactor-mock-to-fake 支持哪些 AI 工具?

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

fdt-refactor-mock-to-fake 需要什么权限?

权限级别是执行命令。安装流程涉及命令执行,可能通过 npx skills add https://github.com/dagster-io/erk --skill fdt-refactor-mock-to-fake 联网下载 Skill 或依赖。用户安装前应确认命令来源、仓库内容和执行环境。

fdt-refactor-mock-to-fake 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

fdt-refactor-mock-to-fake 用的人多吗?

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

fdt-refactor-mock-to-fake 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

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

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 第三方扫描已通过,常见的高风险行为没有命中。

先想清楚的地方

  • 需要执行命令,装到常用环境前要先评估影响面。
  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

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

不太适合

  • 不能接受 Skill 在你机器上执行命令的人。
  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 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调用外部服务未明确有提醒
fdt-refactor-mock-to-fake

fdt 将模拟重构为假 · 本页

21881执行命令未明确通过

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

SKILL.md 原文

Refactoring Mocks to Fakes

Remove unittest.mock.patch from tests by making source code inject gateway dependencies, then configuring pre-canned fakes in tests.

Use this skill when: A test imports from unittest.mock import patch or uses @patch(...) decorators.

Key principle: Don't stop at the lowest-level matching gateway. Look for a higher-level abstraction that covers ALL the things being mocked together.


Phase 1: Audit Mock Usage

Read the test file. For each patch(...) call, record:

Mock target (fully qualified)System boundary (tool)What it simulatesReturn value configured
erk.core.fast_llm.shutil.whichClaude CLICLI availability checkNone or "/usr/bin/claude"
erk.core.fast_llm.subprocess.runClaude CLICLI execution resultCompletedProcess(returncode=0, stdout="...")

The system boundary column identifies which gateway should own this mock. Multiple mocks with the same system boundary should be covered by a single gateway.

Group mocks by test: A single test patching 2-3 things together suggests those things form a unit that should be covered by one injectable gateway.


Phase 2: Gateway Discovery (Critical)

For each mock group, find the right gateway. Do not stop at the first match.

Rule: subprocess.run is never the right gateway boundary. The gateway should be named after the *tool* being invoked (e.g., GhCli, CmuxGateway, GitGateway), not after the underlying mechanism (subprocess, shell). A gateway that just wraps subprocess.run is no better than mocking subprocess.run directly — it skips the meaningful abstraction layer.

Step 1: Identify the system boundary being tested

Ask: what is the test *actually* testing? Not "what function is being patched" but "what behavior is under test?" Think in terms of the *tool or service* being interacted with, not the Python function being called.

Examples:

  • shutil.which("claude") -> "is the Claude CLI installed?" (tool: Claude CLI)
  • subprocess.run(["claude", "--print",...]) -> "run a prompt via Claude CLI" (tool: Claude CLI)
  • Together -> "interact with the Claude CLI" -> gateway is PromptExecutor (Claude-specific), not Shell (subprocess-generic)

Step 2: Targeted gateway search

Before broad exploration, do a quick targeted search using the tool names from Phase 1:

Grep(pattern="<tool_name>", path="packages/erk-shared/src/erk_shared/gateway/")

If zero hits for a tool → no gateway exists for it. You'll need to create one (see Phase 5). If hits → read the matching gateway to assess coverage.

This takes seconds and immediately tells you whether you're in "reuse" or "create" territory.

Step 3: Check if any mock target is already covered

Before creating anything new, check if existing gateways already cover some of your mock targets. A test mocking subprocess.run(["gh", "pr", "view",...]) is already covered by LocalGitHub.get_pr() — no new gateway needed for that mock.

For each system boundary from Phase 1, ask:

  • Does an existing gateway already provide this operation?
  • Can the test use the existing fake instead of mocking subprocess?

This often eliminates half the mocks immediately, reducing the scope of new work.

Step 4: Search for existing gateways at the right abstraction level

Search from highest to lowest. A higher-level gateway is preferable because it covers multiple low-level calls as a unit.

# 1. Search for existing ABCs that describe the behavior
Grep(pattern="class Fake\w+", path="packages/erk-shared/src/erk_shared/")
Grep(pattern="class Fake\w+", path="tests/fakes/")

# 2. Find gateways that mention the system call you're replacing
Grep(pattern="shutil.which|subprocess.run|is_available", path="packages/erk-shared/")

Priority order when multiple gateways match:

  1. A gateway that covers ALL mocked targets in a test -> inject this one
  2. A gateway that covers the highest-level behavior (e.g., PromptExecutor.execute_prompt rather than Shell.get_installed_tool_path)
  3. The lowest-level matching gateway as a last resort

Erk gateway locations:

  • packages/erk-shared/src/erk_shared/gateway/*/abc.py -- gateway ABCs
  • packages/erk-shared/src/erk_shared/gateway/*/fake.py -- matching fakes
  • packages/erk-shared/src/erk_shared/core/fakes.py -- fakes for service ABCs (FakePromptExecutor, FakeLlmCaller, FakeScriptWriter, etc.)
  • tests/fakes/ -- erk-specific fakes

Step 5: Verify the fake covers what you need

Read the fake's __init__ signature. Check:

  • Can you configure the pre-canned responses the test needs?
  • Does the fake record calls for assertion (calls, prompt_calls, etc.)?
  • Does the fake's is_available() return what you need?

If no fake exists at the right level, you'll need to create one (see Phase 5).


Decision Fork: Gateway Found vs. New Gateway Needed

After Phase 2, you're in one of two paths:

Path A: Existing gateway covers all mocks

  • Skip to Phase 3 (plan injection) → Phase 4 (make injectable) → Phase 6 (rewrite tests)
  • This is the fast path. Scope: modify source + rewrite tests.

Path B: No gateway exists for one or more system boundaries

  • You must create a new gateway before rewriting tests
  • Load the gateway-abc-implementation doc (docs/learned/architecture/gateway-abc-implementation.md)
  • Follow Phase 5-expanded below
  • Scope is significantly larger: new gateway files + ErkContext wiring + modify source + rewrite tests

Phase 3: Plan the injection

Identify what source code needs to change.

Where is the mocked code called from?

Read the source file being patched (e.g., erk.core.fast_llm -> src/erk/core/fast_llm.py). Find the class or function that directly calls the mocked thing.

Is there already a constructor parameter for this gateway?

  • Yes -> skip Phase 4, go to Phase 6
  • No -> plan to add a constructor parameter

What's the production wiring?

Find where the class is instantiated in production (usually src/erk/core/context.py). Plan what real implementation to wire in:

  • FallbackPromptExecutor -> ClaudeCliPromptExecutor(console=None)
  • Shell -> RealShell()
  • etc.

Phase 4: Make source code injectable

Add the gateway as a constructor parameter. Follow erk's conventions:

  • Named parameters only (def __init__(self, *, gateway: GatewayABC))
  • No default parameter values -- caller must wire it explicitly
  • Store as self._gateway

Replace direct system calls with gateway method calls:

# Before:
if shutil.which("claude") is None: ...
result = subprocess.run(["claude", "--print", ...])

# After:
if not self._prompt_executor.is_available(): ...
result = self._prompt_executor.execute_prompt(prompt, model=..., ...)

Map gateway return types to the source function's return types. If the gateway returns PromptResult(success, output, error) but the function returns LlmResponse | LlmCallFailed, add the mapping:

if not result.success:
    return LlmCallFailed(message=f"CLI failed: {result.error}")
return LlmResponse(text=result.output)

Update production wiring in context.py:

from erk.core.prompt_executor import ClaudeCliPromptExecutor
MyClass(prompt_executor=ClaudeCliPromptExecutor(console=None))

Variant: Click command injection (exec scripts)

For Click commands (especially exec scripts), use Click's context system instead of constructor injection:

@click.command(name="my-command")
@click.pass_context
def my_command(ctx: click.Context, ...) -> None:
    github = require_github(ctx)       # existing gateway from context
    cmux = require_context(ctx).cmux   # new gateway from context

Replace direct system calls with gateway method calls obtained from context. See src/erk/cli/commands/exec/scripts/AGENTS.md for the full pattern.


Phase 5: Create a new gateway (when no suitable gateway exists)

Load docs/learned/architecture/gateway-abc-implementation.md for full patterns.

Decide: 3-file or 5-file pattern

  • 3-file (abc, real, fake): For all-or-nothing operations, process replacement, or operations where dry-run/printing don't add value. Examples: Codespace, AgentLauncher.
  • 5-file (abc, real, fake, dry_run, printing): For gateways with distinct read vs mutation methods where dry-run preview is useful. Examples: Git, LocalGitHub, Graphite.

Most new gateways for mock-to-fake refactoring use the 3-file pattern.

Gateway creation checklist

  1. Create directory: packages/erk-shared/src/erk_shared/gateway/<tool_name>/
  2. __init__.py — empty
  3. abc.py — ABC with abstract methods named after tool operations (not subprocess)
  4. real.py — Production implementation using subprocess calls to the tool
  5. fake.py — Constructor-injected test data, NamedTuple call tracking, read-only properties

ErkContext wiring checklist

  1. Add <tool>: <ToolABC> field to ErkContext dataclass (packages/erk-shared/src/erk_shared/context/context.py)
  2. Add <tool> parameter to ErkContext.for_test() with default Fake<Tool>(...)
  3. Wire Real<Tool>() in production context factory (src/erk/core/context.py, near other Real* instantiations)

Error handling decision

  • All callers terminate on failure → raise RuntimeError
  • Some callers branch on error → return discriminated union (see Non-Ideal State Decision Checklist in gateway-abc-implementation.md)

Phase 6: Rewrite the tests

For each test that used patch:

  1. Remove from unittest.mock import patch (and any from subprocess import CompletedProcess)
  2. Construct the fake with pre-canned responses
  3. Pass it to the class under test via the new constructor parameter
  4. Replace mock assertions (mock_run.assert_called_once()) with fake property checks (assert len(executor.prompt_calls) == 1)

Pattern:

# Before:
def test_falls_back_to_cli(monkeypatch):
    monkeypatch.delenv("ANTHROPIC_API_KEY", raising=False)
    fake_result = CompletedProcess(args=[], returncode=0, stdout="my-slug\n", stderr="")
    with (
        patch("erk.core.fast_llm.shutil.which", return_value="/usr/bin/claude"),
        patch("erk.core.fast_llm.subprocess.run", return_value=fake_result) as mock_run,
    ):
        result = AnthropicLlmCaller().call("test prompt", system_prompt="sys", max_tokens=50)
    assert isinstance(result, LlmResponse)
    mock_run.assert_called_once()

# After:
def test_falls_back_to_cli(monkeypatch):
    monkeypatch.delenv("ANTHROPIC_API_KEY", raising=False)
    executor = FakePromptExecutor(
        prompt_results=[PromptResult(success=True, output="my-slug", error=None)]
    )
    caller = AnthropicLlmCaller(prompt_executor=executor)
    result = caller.call("test prompt", system_prompt="sys", max_tokens=50)
    assert isinstance(result, LlmResponse)
    assert result.text == "my-slug"
    assert len(executor.prompt_calls) == 1
    assert executor.prompt_calls[0].prompt == "test prompt"

Note: monkeypatch.delenv is a pytest fixture, not mock.patch -- it's fine to keep.


Phase 7: Verify

Run the affected test file:

uv run pytest <test_file> -v

Then lint and type-check the modified source files.


Common pitfalls

Pitfall 1: Matching the wrong gateway level If shutil.which is mocked, the obvious match is Shell.get_installed_tool_path(). But if subprocess.run is also mocked in the same test, the real abstraction is something that covers BOTH -- often PromptExecutor or a similar higher-level gateway.

Pitfall 2: monkeypatch.delenv vs mock.patch monkeypatch.delenv("ANTHROPIC_API_KEY") is a pytest builtin, not mock.patch. Keep it -- it's acceptable and doesn't need replacement.

Pitfall 3: Forgetting to update production wiring After adding a constructor parameter, always update context.py (or wherever the class is instantiated). The type checker will catch this but only if you run it.

Pitfall 4: One test, multiple patch contexts Multiple patch() calls in one test is a red flag that something needs to be at a higher abstraction level. A single fake should replace all of them.

Pitfall 5: Creating a subprocess-level gateway If you find yourself designing a gateway called ShellRunner, SubprocessGateway, or CommandRunner, stop. That's still mocking at the wrong level. The gateway must be specific to the *tool* being called:

  • subprocess.run(["gh",...]) → LocalGitHub or a GhCli gateway
  • subprocess.run(["cmux",...]) → CmuxGateway
  • subprocess.run(["claude",...]) → PromptExecutor
  • subprocess.run(["git",...]) → Git gateway

Name the gateway after what it represents, not how it executes.

平台分布

Codex

32.75%
按下载量换算23

Claude

30.6%
按下载量换算22

Cursor

18.05%
按下载量换算13

Gemini CLI

9.6%
按下载量换算7

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

执行命令

安装流程涉及命令执行,可能通过 npx skills add https://github.com/dagster-io/erk --skill fdt-refactor-mock-to-fake 联网下载 Skill 或依赖。用户安装前应确认命令来源、仓库内容和执行环境。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills