2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Rxとテスト戦略:マーブルテスト・仮想時間制御の実際

Posted at

概要

非同期処理・時間を含むロジックのテストは、
しばしば「実行待ち」「タイミングのズレ」「偶発的成功」などの問題を招く。

RxJSはこの問題を根本から解決する手段として、「仮想時間」によるマーブルテストを導入している。
本稿では、Rxにおけるテストの哲学とマーブル記法、そして時間を制御可能にする設計的恩恵を構造的に解説する。


1. 非同期のテストが難しい理由

  • 時間軸に依存(setTimeout, debounceTime, delay…)
  • 外部要因に左右されやすい(ネットワーク、UIイベント等)
  • 再現性の低いバグが潜む

実時間ベースでは再現性が不安定になりやすい


2. マーブルテストとは何か?

「仮想時間上のストリームの動きを、記号で表現して検証するテスト手法」

--a--b---c--|

このようなマーブル文字列で、Observableの挙動を視覚的・構造的に定義できる。

  • - : 仮想時間の1フレーム
  • a, b, c : nextで発行された値
  • | : complete
  • # : error

3. TestScheduler を用いたマーブルテストの構造

import { TestScheduler } from 'rxjs/testing'
import { map } from 'rxjs'

const testScheduler = new TestScheduler((actual, expected) => {
  expect(actual).toEqual(expected)
})

testScheduler.run(({ cold, expectObservable }) => {
  const source = cold('--a--b--c--|')
  const expected =       '--x--y--z--|'

  const result = source.pipe(
    map((value) => value.toUpperCase())
  )

  expectObservable(result).toBe(expected, { x: 'A', y: 'B', z: 'C' })
})
  • cold():Observableの仮想定義
  • expectObservable():その出力結果をマーブル記法で検証
  • 時間と値を構造的に検証できる

4. run()モードによる時間の抽象化

TestScheduler.run() によって、すべての演算子(debounceTime, delay, switchMapなど)も仮想時間で動作させられる。

これにより:

  • テスト高速化(リアル時間不要)
  • 時間依存バグの再現
  • タイミングによる競合のデバッグが容易

5. 応用:debounceTime のマーブルテスト

testScheduler.run(({ cold, expectObservable }) => {
  const input = cold('a--a---a----|')
  const expected =     '--- --- ----(a|)'

  const result = input.pipe(debounceTime(5))

  expectObservable(result).toBe(expected)
})

debounceTime によって 最後の1つだけが遅れて出力されることを検証


6. 効果的なRxテスト戦略

パターン アプローチ
時間が関与する処理 TestScheduler.run() + マーブル記法
非同期API呼び出し ストリームをstub化 / switchMapの挙動検証
UIイベントの反映 fromEvent 相当の cold observable で再現

よくある誤解と対策

❌ マーブル記法は覚えにくい

→ ✅ 最初はそう感じるが、視覚的な時系列表現が頭に残りやすく、ロジックの理解に直結する


❌ Rxのテストは遅くて書きにくい

→ ✅ 仮想時間ベースであれば、超高速・高再現性のテストが可能


❌ 普通のテスト(Jest)で十分では?

→ ✅ Promise ベースのテストでは、タイミングに依存するUI処理や連続API呼び出しの制御が困難


結語

非同期はテストが難しい──
それは「時間」と「順序」という“見えない変数”が常に絡むからである。

Rxのマーブルテストは、
その見えない流れを構造として可視化し、設計・検証の対象へと変換する技術である。

リアクティブなテスト戦略とは、
“非同期の振る舞いを仮想空間に引き上げ、抽象的に設計し、再現可能に制御するための思想である。”

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?