怎么用 TestSchema.Asserts 测 Effect Schema?

给 Schema 写测试,最容易写成一堆手工构造的输入输出对,还总漏掉「编码再解码是否还原」这种性质。

**用 effect/testing 里的 TestSchema.Asserts:new TestSchema.Asserts(schema) 之后,用 decoding()、encoding() 断言具体输入输出,用 verifyRoundTrip 做往返,用 arbitrary().verifyGeneration 检查生成器。**它在内部用属性测试的方式生成输入,失败时带 shrink 后的输入和 replay。

Schema 是 Effect 里描述并校验运行时数据形状的那套定义,没接触过的话先看TypeScript 类型保护不了运行时数据,该怎么校验?;生成输入的机制见 Effect v4 不用 fast-check,属性测试怎么写?。下面先列方法,再看一个完整的 vitest 例子。

TestSchema.Asserts 有哪些方法?

  • decoding().succeed(input, expected?) 和 decoding().fail(input, message):断言解码结果或格式化后的错误信息。
  • encoding().succeed(value, expected?):断言编码结果。
  • verifyRoundTrip(options?):对生成的值做「编码再解码」,断言与原值深度相等,失败时带 shrink 后的输入和 replay。
  • arbitrary().verifyGeneration(options?):检查生成器产出的值都满足 Schema。
  • decoding 和 encoding 另有 succeedEffect、failEffect,往返有 verifyRoundTripEffect,返回惰性的 Effect,用于需要服务的 Schema。

在 vitest 里怎么写?

import { describe, it } from "@effect/vitest"
import { Schema } from "effect"
import { TestSchema } from "effect/testing"

class Payment extends Schema.Class<Payment>("Payment")({
  id: Schema.Int,
  amount: Schema.NumberFromString
}) {}

describe("Payment schema", () => {
  const asserts = new TestSchema.Asserts(Payment)

  it("编码", async () => {
    await new TestSchema.Asserts(Schema.NumberFromString).encoding().succeed(42, "42")
  })

  it("解码失败的信息", async () => {
    await asserts
      .decoding({ parseOptions: { errors: "all" } })
      .fail({ id: 1.5, amount: 5 }, [
        "Expected an integer",
        "  at [\"id\"]",
        "Expected string",
        "  at [\"amount\"]"
      ].join("\n"))
  })

  it("往返", async () => {
    await asserts.verifyRoundTrip({ runs: 50, seed: 3 })
    asserts.arbitrary().verifyGeneration({ seed: 1 })
  })
})

解码失败的信息要断言多细?

decoding().fail 断言的是完整的格式化文本。上面的例子里,errors: "all" 让所有字段的错误都出现,而不是第一个就停,所以 id 和 amount 两处错误都在期望文本里。如果只关心第一个错误,就不要传这个选项。

对象 Schema 的往返为什么有时会失败?

verifyRoundTrip 对 Schema.Class 的实例和纯原始类型的 Schema 工作正常,上面的 Payment 就能通过;但对 Schema.Struct 在 4.0.5 上会失败,即使 Schema 完全正常。原因和绕法见 Schema.Struct 上的 verifyRoundTrip 为什么失败?。

这个模块稳定吗?

TestSchema 在 JSDoc 里标注为 @stability unstable,方法名和行为都可能变。

版本是 effect 4.0.5、@effect/vitest 4.0.5、vitest 5.0.5。上面的例子是在这个版本组合上跑过的。@stability unstable 读自 JSDoc;各个方法的签名按 4.0.5 整理,没有对照其它版本逐一验证。