モックではなく実際のメソッドで呼び出したい典型的なケース

モックではなく実際のメソッドで呼び出したい典型的なケースとしては、メソッドが単なる文字列整形・変換だったり数値計算だったり、他のクラスに依存しないような処理がある。

SomeServiceというクラスがあり、SomeRepositoryに依存しているとする。SomeServiceの各メソッドは基本的にSomeRepositoryを通してDBアクセスなどを行なっているとする。各メソッドは当然staticメソッドとしては実装できない。

@Service
@RequiredArgsConstructor
public class SomeService {

    private final SomeRepository someRepository;

    public int create() {
        return someRepository.save();
    }

    // 略
}

メソッドが単なる文字列整形・変換だったり数値計算だったりして、SomeRepositoryには依存しない処理の場合は、staticメソッドとして実装できる。

public static int calc(int param1, int param2) {
    // 略
}

Spring BootでServiceクラスを実装する際にstaticメソッドにすることは通常ないが、このようにstaticメソッドとしても実装できるようなメソッドは、モック化せず実際の処理を通しても問題ないどころか、逆にテストがわかりやすくなることが多い。

一部のメソッドをモックではなく実際のメソッドで呼び出す

@Spy

一部のメソッドをモックではなく実際のメソッドで呼び出す方法としてMockitoの@Spyがある。

以下のどちらかの書き方でSomeServiceクラスのインスタンスを生成する。

書き方1

@ExtendWith(MockitoExtension.class)
public class SomeControllerTest {

    @InjectMocks
    SomeController someController;

    @Mock
    SomeRepository someRepository;

    @InjectMocks
    @Spy
    SomeService someService;
}

書き方2

@ExtendWith(MockitoExtension.class)
public class SomeControllerTest {

    @InjectMocks
    SomeController someController;

    @Mock
    SomeRepository someRepository;

    @Spy
    SomeService someService = new SomeService(someRepository);
}

someService.method1();のようなメソッド呼び出しがテスト実行対象のメソッド内でされたとき、@SpyではdoReturnなどでモック化しない限り、実際のメソッドが実行される。

doCallRealMethod

@Mockでモック化したインスタンスに対してdoCallRealMethodを使うことでも、メソッドをモックではなく実際のメソッドで呼び出すことができる。

doCallRealMethod().when(someService).method1(any());

このように書くことで、someService.method1();のようなメソッド呼び出しがテスト実行対象のメソッド内でされたとき、実際のメソッドが実行される。

@MockSomeServiceをモック化するときは、SomeServiceが依存しているSomeRepositoryについて書く必要がない。

@ExtendWith(MockitoExtension.class)
public class SomeControllerTest {

    @InjectMocks
    SomeController someController;

    @Mock
    SomeService someService;
}

doCallRealMethod vs @Spy

doCallRealMethod@Spyのどちらを積極的に使用すべきかについては、クラスの各メソッドのどれだけの割合が実際のメソッド呼び出しになるかで決まる。

モック化されるメソッドが大半で1, 2個のメソッドのみが実際のメソッド呼び出しなのであれば、モック化がデフォルトの@Mockを使用して、1, 2個のメソッドのみdoCallRealMethodで実際のメソッド呼び出しができるようにすればいい。

反対に、基本的に全て実際のメソッド呼び出しをする中で一部だけモック化したい場合は、@Spyを使うべき。