「service層をモックしてテストケースを作成しておいてー」
特に違和感なく通じる方が多数だと思います。
もちろん自分も
「service層をモックしてテストケースねうんうん」
という感じですぐ理解できます。
なんなら、エンジニア初級者でもモックねうんうんという方が多数だと思います。
ただ、スタブと言われるとスタブ?なんだっけ?と思われる方がいらっしゃるのではないでしょうか?
皆さんが思っているのそもそもモックではなくスタブですよーというお話です。
スタブってなんだっけ?
スタブとは
「特定の入力に対して、あらかじめ決めた値を返すだけの代替実装」です。
あれ?それモックじゃないの?という方もいると思います。(そういう方向けに記事を作成しています。)
実装例
when(userRepository.findById(1L)).thenReturn(Optional.of(user));
userRepository.findById(1L) が呼ばれたらOptional.of(user)を返す
という 振る舞いを差し替えているだけです
→これがスタブの役割です。
じゃあモックとは?
モックとは
「呼ばれたかどうかを検証するためのもので、副作用や呼び出し回数をチェックする」です。
実装例
verify(service,times(1)).process(user);
verify(service,never()).delete(any());
検証対象のメソッドに対して
・呼ばれたか
・何回呼ばれたか
・どんな引数で呼ばれたか
・呼ばれた順序
といった interaction(相互作用) を検証しています。
そう言えばドライバって何?
ドライバとは
「Service層等を(=SUT)をモックせずに 実際に呼び出している側」
のことです。
実装例
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
UserRepository userRepository; // 下流はモック(スタブ)
@InjectMocks
UserService userService; // ← これは本物
@Test
void findUser() {
when(userRepository.findById(1L))
.thenReturn(Optional.of(new User("taro")));
// ドライバ(SUTを呼ぶ)
User user = userService.find(1L);
assertEquals("taro", user.getName());
}
}
テストコードでテスト対象(SUT)のメソッドを呼び出している部分が「ドライバ」というわけですね。
最後に
今回この記事を書いたのはservice層をモックしてーって言われてなんとなく理解していたけどじゃあスタブってなんだっけ?と思ったからです。
中堅社員だとこの言い方でいいと思いますが、初級者エンジニアにはスタブとモックの違いを理解するために説明くらいはしてもいいかもしれないと思った次第です。