Lua Academy · レッスン

モックとスパイ

テスト対象のコードを分離します。

レッスン 4/413 ステップ

「モックとスパイ」はCoddyKit上の無料Lua Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはLua Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Lua Academyコースには全4レッスンが含まれています。

テストダブル

関数が、ネットワーク呼び出しやロガーのような低速または外部のものに依存する場合があります。テストダブルは、そうした依存関係を制御可能な代替に置き換えます。

bustedには、スパイ、スタブ、モックの3種類があります。それぞれ異なる用途に使います。

スパイの役割

スパイは関数をラップし、元の関数を実行しながら呼び出し方を記録します。何かが呼び出されたことを確認できます。

関数をspy.newでラップして作成するか、テーブルのフィールドをスパイします。

local s = spy.new(function() end)
s(1, 2)
assert.spy(s).was.called()

メソッドのスパイ

spy.onを使うと、既存のテーブルにあるメソッドを監視できます。元のメソッドは引き続き実行されますが、bustedが各呼び出しを追跡します。

ロガーが呼び出されたことを確認するなど、副作用の確認に適しています。

spy.on(logger, "info")
service.run()
assert.spy(logger.info).was.called()

呼び出し回数の確認

スパイは呼び出された回数を記録します。正確な回数を確認するにはwas.called(n)を使います。

これにより、関数が呼ばれすぎたり、まったく呼ばれなかったりするバグを見つけられます。

assert.spy(s).was.called(2)
assert.spy(s).was_not.called()

呼び出し引数の確認

was.called_withを使うと、スパイが受け取った引数を確認できます。bustedが記録された引数と期待する値を比較します。

関数が実行されたことだけでなく、正しく実行されたことも確認できます。

local s = spy.new(function() end)
s("user", 42)
assert.spy(s).was.called_with("user", 42)

スタブの役割

スタブは関数を完全に置き換えるため、元の関数は実行されません。実際のネットワークアクセスやディスクアクセスなど、低速または望ましくない処理を省略するために使います。

テーブルのフィールドにstubを使って作成します。デフォルトでは、スタブは何もせずnilを返します。

stub(api, "fetch")
service.load()
assert.stub(api.fetch).was.called()

スタブの戻り値

returnsを使うと、スタブに固定値を返させることができます。これにより、テスト対象のコードに制御されたデータを渡せます。

これで、テストは実際の依存関係にまったく依存しなくなります。

stub(api, "fetch").returns({id = 1})
local r = service.load()
assert.are.same({id = 1}, r)

モックの役割

モックは既存のテーブルを受け取り、その中のすべての関数を一度にスパイまたはスタブに変換します。オブジェクト全体を追跡する便利な方法です。

mock(obj)を呼び出してラップし、その後で個々のメソッドを確認します。

local m = mock(realLogger)
app.start(m)
assert.spy(m.warn).was.called()

メソッドをスタブ化したモック

mockの2番目の引数にtrueを渡すと、すべてのメソッドがスタブ化されるため、元のメソッドは実行されません。これにより、オブジェクトを完全に分離できます。

実際のメソッドに避けなければならない副作用がある場合に使います。

local db = mock(database, true)
db.query.returns({})
assert.are.same({}, repo.all())

テストダブルの復元

スパイ、スタブ、モックは共有テーブルを変更するため、復元しなければ後続のテストからもそのテストダブルが見えてしまいます。:revert()またはmock.revertを呼び出します。

テスト間で状態を確実にクリーンに保つため、復元処理をafter_eachに配置します。

after_each(function()
  mock.revert(m)
end)

適切なテストダブルの選択

実際の関数を観察するにはスパイを、制御された動作に置き換えるにはスタブを、オブジェクト全体を一度にラップするにはモックを使います。

目的を達成できる最も軽量なテストダブルを選びます。モックを使いすぎると、テストが壊れやすくなり、実際のバグを隠してしまうことがあります。

describe("mailer", function()
  it("sends once", function()
    local s = spy.on(smtp, "send")
    mailer.notify("a@b.com")
    assert.spy(s).was.called(1)
  end)
end)

理解度チェック

bustedのテストダブルについて理解度を確認しましょう。

まとめ

テストダブルは、低速な依存関係や外部依存関係からコードを分離します。スパイは元の関数を実行しながら呼び出しを記録し、スタブは制御された動作を持つ関数に置き換え、モックはオブジェクト全体をラップします。

was.calledとwas.called_withで確認し、テストを分離した状態に保つため、必ずafter_each内でrevertを使ってテストダブルを復元します。

無料で開始

AI チューターと学ぶ Lua — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
40
レッスン
159

よくある質問

「モックとスパイ」レッスンは無料ですか?

はい。「モックとスパイ」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Lua Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Lua Academyコースには全4レッスンが含まれています。

「モックとスパイ」で何を学びますか?

テスト対象のコードを分離します。 ブラウザで直接実行するハンズオンコードでLua Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Lua Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのLua Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「モックとスパイ」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このLua Academyレッスンでコードを書いて実行できますか?

はい。すべてのLua Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. テストする理由
  2. describeブロックとitブロック
  3. アサーション
  4. モックとスパイ
← Lua Academyに戻る