はじめに

前回の続きです。

前回は、基本的な文法を確認しました。今回は、モック機能を使ってみます。

テスト対象コード

想定としては、MockSampleが自分が開発しているコード。MessageManagerが他人が開発しているコードとします。

MessageManagerクラスの開発は遅延しているので、インタフェースだけ先に提供されているものとします。

こんなとき、自分が作ったMockSampleクラスをMessageManagerの依存関係をうまく扱ってテストすることを目指します。

  • MockSample.java
package sample;

public class MockSample {
    private MessageManager mgr;

    public void setManager(MessageManager mgr) {
        this.mgr = mgr;
    }

    public void sendMsg(String msg) {
        mgr.send(msg);
    }

    public int sendMsg2(String msg) {
        return mgr.send2(msg);
    }
}
  • MessageManager.java
package sample;

public interface MessageManager {
    void send(String msg);
    int send2(String msg);
}

テストコード

モックとスタブの言葉の定義は人それぞれあって混乱するのだけれども、ここでは

  • モック: 呼びだされたときに与えられるパラメータチェックと呼び出し回数をチェックするダミークラス
  • スタブ: 呼びだされた時に戻り値を返すダミークラス

とします。

モック

まずは、モックから。Mockを生成するには、

def mgr = Mock(MessageManager)

とするか、

MessageManager mgr = Mock()

で宣言します。

import sample.MessageManager
import sample.MockSample
import spock.lang.Specification

class MockSampleSpec extends Specification {

  def "呼び出し引数をチェック(Mocking)"() {
      setup:
      def sample = new MockSample()
      def mgr = Mock(MessageManager)
      sample.setManager(mgr)

      when:
      sample.sendMsg("hello")
      sample.sendMsg("hello")

      then:
      2 * mgr.send("hello")
  }
}

以下で2回呼び出しを期待して、呼び出し引数は"hello"を期待しています。

2 * mgr.send("hello")

スタブ

次にスタブです。以下の宣言で、戻り値をオブジェクトに指定します。

mgr.send2(_) >> 1
def "戻り値を返す(Stubbing)" () {
    setup:
    def sample = new MockSample()
    def mgr = Mock(MessageManager)
    mgr.send2(_) >> 1
    sample.setManager(mgr)

    expect:
    sample.sendMsg2("hello") == 1
}

例外をチェックするテストコード

戻り値の代わりに例外をスタブで発生させることもできます。

def "例外が発生したことを確認する" () {
    setup:
    def sample = new MockSample()
    def mgr = Mock(MessageManager)
    mgr.send(_) >> {throw new IllegalArgumentException()}
    sample.setManager(mgr)

    when:
    sample.sendMsg("hoge")

    then:
    thrown(IllegalArgumentException)
}

また、なにも例外が発生しなかったことを確認することもできます。

def "例外が発生しないことを確認する" () {
    setup:
    def sample = new MockSample()
    def mgr = Mock(MessageManager)
    sample.setManager(mgr)

    when:
    sample.sendMsg("hello")

    then:
    noExceptionThrown()
}

コードはgithubにもあげています。

参考

今日はここまで!