@effect/vitest
https://www.npmjs.com/package/@effect/vitest
#wip
GPT-4.icon
table:table
機能 説明
----------------- ------
it.effect TestContext を自動提供(テストクロックなどが使える)
it.live 実環境でテストを実行(リアルな時間やロギングなど)
it.scoped Scope(リソース管理)を必要とするEffect用
it.scopedLive scoped + live の両方
it.flakyTest 不安定なテストに対してリトライを行う仕組み
---
🧪 基本的なテストの書き方
正常系のテスト
code:ts
it.effect("正常に割り算できる", () =>
Effect.gen(function* () {
const result = yield* divide(4, 2)
expect(result).toBe(2)
})
)
エラーも扱いたい(Exit を使う)
code:ts
it.effect("ゼロ除算のエラーを検知", () =>
Effect.gen(function* () {
const result = yield* Effect.exit(divide(4, 0))
expect(result).toStrictEqual(Exit.fail("Cannot divide by zero"))
})
)
---
⏰ テスト中に時間を制御したい(TestClock)
code:ts
it.effect("時間を進めてテスト", () =>
Effect.gen(function* () {
yield* TestClock.adjust("1000 millis")
const now = yield* Clock.currentTimeMillis
console.log(now) // -> 1000
})
)
※ it.live を使うとリアルな時間も利用可能
🔁 不安定なテスト(flaky)をリトライさせる
code:ts
it.effect("不安定なテストのリトライ", () =>
it.flakyTest(flaky, "5 seconds")
)
♻️ Scope付きのテスト(リソース管理)
code:ts
it.scoped("スコープ管理付きのテスト", () =>
Effect.gen(function* () {
yield* resource // acquireReleaseを使用
})
)
✅ 成功と失敗をExitで扱う(Effect.exit)
解説
通常のEffectは失敗すると途中で中断しますが、Effect.exitを使うと、成功・失敗のどちらもExitオブジェクトに変換して返すので、両方をテストで安全に検証できます。
code:ts
const result = yield* Effect.exit(divide(4, 2))
expect(result).toStrictEqual(Exit.succeed(2)) // 成功ケース
const result = yield* Effect.exit(divide(4, 0))
expect(result).toStrictEqual(Exit.fail("Cannot divide by zero")) // 失敗ケース
⏭ テストのスキップと限定実行
it.effect.skip(...) → 一時的に無効化したいとき
it.effect.only → 特定のテストだけを実行したいとき
❌ 失敗を許容するテスト(it.effect.fails)
解説
まだ失敗しているテストを明示的に残したいときに使います。将来修正されてテストが通るようになったら、失敗を期待していたが成功したことで逆に通知されるので、回帰の検知にもなります。
code:ts
it.effect.fails("temporary failing test", ({ expect }) =>
Effect.gen(function* () {
const result = yield* Effect.exit(divide(4, 0))
expect(result).toStrictEqual(0) // 本当は失敗するので、これでOK
})
)
🪵 ログ出力の制御
it.effectではログはデフォルトで抑制される(静かにしたいときに便利)。
Logger.prettyを明示的に提供することでログを表示できる。
it.liveでもログが表示される。
code:ts
import { it } from "@effect/vitest"
import { Effect, Logger } from "effect"
// This test won't display the log message, as logging is suppressed by default in it.effect
it.effect("does not display a log", () =>
Effect.gen(function* () {
yield* Effect.log("it.effect") // Log won't be shown
})
)
// This test will display the log because a custom logger is provided
it.effect("providing a logger displays a log", () =>
Effect.gen(function* () {
yield* Effect.log("it.effect with custom logger") // Log will be displayed
}).pipe(
Effect.provide(Logger.pretty) // Providing a pretty logger for log output
)
)
// This test runs using it.live, which enables logging by default
it.live("it.live displays a log", () =>
Effect.gen(function* () {
yield* Effect.log("it.live") // Log will be displayed
})
)
🧹 リソース管理つきテスト(it.scoped)
解説
スコープ付きリソース(例えばacquireReleaseで取得したファイルやDB接続など)をテスト終了時に自動でクリーンアップするために使います。
code:ts
it.scoped("run with scope", () =>
Effect.gen(function* () {
yield* resource // acquire → テスト → release
})
)
it.effectではスコープがないため、リソースの解放ができずエラーになる。
🎲 不安定なテストの扱い(it.flakyTest)
解説
外部依存やランダム性のあるテストに対して、一定時間までリトライを許容することで「たまたまの失敗」に強くなります。
code:ts
it.effect("retrying until success or timeout", () =>
it.flakyTest(flaky, "5 seconds")
)
※flakyはたまたま成功・失敗する処理の例(Random.nextBoolean)