Effect Atom 的测试怎么替换 Layer?

要测「后端挂了界面显示什么」,常见做法是 mock 掉请求模块或起一个 mock 服务器,测完还要小心清理。

用 Atom 不需要 mock 模块:runtime.layer 本身是一个 atom,通过 registry 的 initialValues 把它替换成测试用的 Layer 即可,业务 atom 与组件一行都不用改。

这是 Layer 注入真正的回报:依赖从类型里进来,测试时换一个实现就行。Atom 与 Atom.runtime(layer) 的基本写法见 用 Effect 写 React 前端,状态该怎么管?;通用的 Effect 测试思路见 Effect 代码怎么测试,才不用 mock 整个模块?。

怎么替换 Atom 用到的 Layer?

不用 mock 模块,换 Layer 就行。runtime.layer 本身是一个 atom,所以可以通过 registry 的 initialValues 把它替换成测试用的 Layer,业务 atom 与组件一行都不用改:

// todos-swap.ts
import { Effect, Layer } from "effect"
import { AsyncResult, AtomRegistry } from "effect/reactivity"
import { runtime, TodoApi, TodoError, todosAtom } from "./todos.ts"

const Broken = Layer.succeed(TodoApi, {
  list: Effect.fail(new TodoError({ reason: "backend down" })),
  add: () => Effect.fail(new TodoError({ reason: "backend down" }))
})

const registry = AtomRegistry.make({ initialValues: [[runtime.layer, Broken]] })
registry.mount(todosAtom)
await new Promise((r) => setTimeout(r, 30))

console.log(
  AsyncResult.matchWithError(registry.get(todosAtom), {
    onInitial: () => "initial",
    onError: (e) => `error: ${e.reason}`,
    onDefect: () => "defect",
    onSuccess: () => "success"
  })
)

输出是 error: backend down,说明替换生效了。通用的 Effect 测试思路见 Effect 代码怎么测试,才不用 mock 整个模块?。

为什么这样测比 mock 更稳?

「接口挂了界面怎么显示」可以在没有网络、没有 mock 服务器的情况下被稳定测试,被替换的只是依赖的实现,不是被测的代码路径。

React 组件里怎么做同样的事?

对应的是 RegistryProvider 的 initialValues 属性,机制相同。

版本是 effect@4.0.5。上面的脚本在本地跑过,输出是 error: backend down;RegistryProvider 的 initialValues 属性我只是按机制对应写出,没有单独在组件里跑过。