【テスト駆動開発】スタブ、モック、フェイク、ダミーの違いとは?
どうもこんにちは! こんばんは! れおりんです!
プログラミングをしてテストを記述するときに、モックオブジェクトとか、スタブとかフェイクとか色々な用語があって混乱しますね? 僕は混乱します。開発の打ち合わせなどで開発者間で用語の統一ができておらず、さらに混乱するという場面もありますね。
今回は、それらの違いを説明してみたいと思います。
> スタブスタブ
スタブは日本語だと、「代用部品」となるようです。
スタブは、実際の挙動をシミュレートしてテスト実行の支援をするためのものです。スタブとなっているオブジェクトは入力によって出力が変化するようなもの作れますが、とにかく一定の値を返すようなオブジェクトをスタブと呼ぶときが多いように感じます。
オブジェクトの関連のなかで、スタブは他のオブジェクトには依存しません。単純に値やオブジェクトを返却するだけです。
class UserDatabaseStub {
def getUserById(userId: Int): User = {
userId match {
case 123 => User(123, "Alice")
case 456 => User(456, "Bob")
}
}
}
jMockやScalaMockといったライブラリを使うと、スタブも作成もライブラリに任せることができます。上の例では自力で実装していますが、ある程度の規模だとスタブの実装も時間がかかりますので、ライブラリを活用していきましょう。
以下の例は、ScalaMockを使ってユーザオブジェクトを返すUserDatabaseスタブを作成する例です。
val usersDb = stub[UsersDatabase]
(usersDb.getUserById _) when(123) returns(User(123, "Alice"))
(usersDb.getUserById _) when(456) returns(User(456, "Bob"))
assert(usersDb.getUserById(123).name == "Alice")
> モックモック
モックは日本語だと、「模擬の」という意味ですね。モックはスタブと似ていますが、モックはエクスペクテーションを確認するために使います。エクスペクテーションとは、あるオブジェクトが隣接のオブジェクトとどのような連携をするのかを確かめるためのものです。
モックは自分で実装する手間を省くために、jMockや、ScalaMockなどのライブラリに任せてしまう場合が多いと思います。
以下の例は、UserRepositoryが期待通りにApplicationServiceから使われているかを確認するScalaMockを使ったテストです。
def testAuthentication {
val expectedUser = User(123, "Alice")
val mockedUserRepository = mock[UserRepository]
(UserRepository.getUserByEmailAddress _).expects("alice@example.org").returning(expectedUser)
(UserRepository.updateRecentlyAccessedUser _).expects(expectedUser)
val authApplicationService = new AuthApplicationService(mockedUserRepository)
authApplicationService.auth("alice@example.org", "dummy-password"))
}
> フェイクフェイク
フェイクは日本語だと「偽物」ですね。よくあるフェイクオブジェクトの使われ方は、プロダクション環境では本物のデータベースだけど、単体テスト環境ではインメモリ(データベースの偽物)というのが多いですね。
MySQLUserRepositoryが実際のレポジトリで、FakeはInMemoryRepositoryの様に使われます。
> ダミーダミー
ダミーは日本語だと「仮」となります。単純にダミーの値が渡されるだけで、テスト対象にはなりません。例えばダミーのメールアドレスや、パスワードといったリテラルに近い値やオブジェクトに使われます。