マーブルテスト入門 
RxJSでは、非同期ストリームの挙動を視覚的に表現しながらテストできる「マーブルテスト」という手法が用意されています。
ここでは、マーブルテストの基礎から、簡単な例を通して学びます。
マーブル記法とは? 
マーブル記法は、時間経過とイベント発生を文字列で表現する方法です。
基本ルール 
| 記号 | 意味 | 
|---|---|
- | 時間の経過(1フレーム進む) | 
a, b, c | 発行された値(任意の文字) | 
| ` | ` | 
# | エラー(error) | 
例えば
text
--a-b--c-|これは、
- 2フレーム待って
aが発行 - 1フレーム後に
b - 2フレーム後に
c - さらに1フレーム後に完了 を意味します。
 
ColdとHotの違い 
Cold Observable 
Cold Observableは「購読ごとに最初から再生」されます。
ts
import { TestScheduler } from 'rxjs/testing';
import { describe, it, beforeEach, expect } from 'vitest';
describe('TestSchedulerの基本', () => {
  let testScheduler: TestScheduler;
  beforeEach(() => {
    testScheduler = new TestScheduler((actual, expected) => {
      expect(actual).toEqual(expected);
    });
  });
  it('簡単なテスト', () => {
    testScheduler.run(({ cold, expectObservable }) => {
      const source$ = cold('--a--b--c|');
    
      expectObservable(source$).toBe('--a--b--c|');
    });
  });
});Hot Observable 
Hot Observableは「既に進行中」のストリームです。
 途中から購読した場合、その時点以降の値しか受け取れません。
ts
import { TestScheduler } from 'rxjs/testing';
import { describe, it, beforeEach, expect } from 'vitest';
describe('TestSchedulerの基本', () => {
  let testScheduler: TestScheduler;
  beforeEach(() => {
    testScheduler = new TestScheduler((actual, expected) => {
      expect(actual).toEqual(expected);
    });
  });
  it('簡単なテスト', () => {
    testScheduler.run(({ hot, expectObservable }) => {
      const source$ = hot('--a--b--c|');
    
      expectObservable(source$, '----^').toBe('-----b--c|');
    });
  });
});マーブルテストの簡単な例 
たとえば、debounceTimeオペレーターをテストする場合
ts
import { debounceTime } from 'rxjs';
import { TestScheduler } from 'rxjs/testing';
import { describe, it, beforeEach, expect } from 'vitest';
describe('TestSchedulerの基本', () => {
  let testScheduler: TestScheduler;
  beforeEach(() => {
    testScheduler = new TestScheduler((actual, expected) => {
      expect(actual).toEqual(expected);
    });
  });
  it('簡単なテスト', () => {
    testScheduler.run(({ cold, expectObservable }) => {
      const source$ = cold('--a--b----c|');
      const result$ = source$.pipe(
        debounceTime(20)
      );
    
      const expected =    '-----------(c|)';
    
      expectObservable(result$).toBe(expected, { c: 'c' });
    });
  });
});ここでは、最後に発行されたcだけが出力されることを検証しています。
注意点 
- マーブル記法の1文字はデフォルトで**1フレーム(10ms)**を表します(環境によって設定可)
 debounceTime,delay,intervalなど、時間依存のオペレーターはマーブルテストと相性が良いですexpectObservableを使ってストリームの出力を検証しますexpectSubscriptionsは、サブスクリプションのタイミングを検証する上級機能ですが、ここでは扱いません
まとめ 
マーブルテストは、RxJSコードのテストを可視化し直感的に理解できる非常に強力な手法です。
- ColdとHotの違いを意識する
 - 時間経過とイベントを文字列で表現する
 - 複雑な非同期ストリームも、明快なテストが可能になる
 
まずはシンプルなマーブルテストから練習してみましょう!