Edited at

Spring スーパークラスのモック化

springでスーパークラスをモック化したテストが実行できず、しばらくはまってしまった件。

モック化するクラスを特定させる必要がありました。


失敗例

Spring Boot 2.0.5 で確認してます

継承関係のある2つのクラスを用意します。

これらは@Componentを付けて、DIコンテナに突っ込んでます。

スーパークラス

@Component

public class SuperClass {

void superClassMethod() {
System.out.println("スーパークラスのメソッドを呼び出しました。");
}
}

サブクラス

@Component

public class SubClass extends SuperClass {

void subClassMethod() {
System.out.println("サブクラスのメソッドを呼び出しました。");
}
}

@MockBeanでスーパークラスをモック化して使うテストを書きます。

テストコード

@RunWith(SpringJUnit4ClassRunner.class)

@SpringBootTest
public class SampleTest {

@MockBean
SuperClass superClass;

@Test
public void sampleTest() {
doNothing().when(superClass).superClassMethod();
}
}

実行します。

テスト実行結果

Caused by: java.lang.IllegalStateException: Unable to register mock bean com.example.vendingmachine.sample.SuperClass expected a single matching bean to replace but found [subClass, superClass]

無事死亡。


何がダメなのか

例外メッセージを見ると、以下の記述があります。

expected a single matching bean to replace but found [subClass, superClass]

要するに「モック化対象がsubClassとsuperClassの2つあるため、どっちをモック化したらいいか分かんないです」ということ。

モック化対象クラスにサブクラスが存在する場合、そちらもモック化対象と判定されてしまう。


解決策

以下のように@Queliferを使って「スーパークラスをモック化するんだ!」と宣言すればよいです。

@RunWith(SpringJUnit4ClassRunner.class)

@SpringBootTest
public class SampleTest {

@MockBean
@Qualifier("superClass")
SuperClass superClass;

@Test
public void sampleTest() {
doNothing().when(superClass).superClassMethod();
}
}


@SpyBeanの場合

メソッド単位でモック化できる@SpyBeanの場合も同じ感じでエラーになります。

テストコード

@RunWith(SpringJUnit4ClassRunner.class)

@SpringBootTest
public class SampleTest {

@SpyBean
SuperClass superClass;

@Test
public void sampleTest() {
doNothing().when(superClass).superClassMethod();
}
}

テスト実行結果

java.lang.IllegalStateException: No bean found for definition [SpyDefinition@f2b90fc name = '', typeToSpy = com.example.vendingmachine.sample.SuperClass, reset = AFTER]

この場合は、以下のように@SpyBeanname属性にスーパークラス名を入れればOKです。

@RunWith(SpringJUnit4ClassRunner.class)

@SpringBootTest
public class SampleTest {

@SpyBean(name = "superClass")
SuperClass superClass;

@Test
public void sampleTest() {
doNothing().when(superClass).superClassMethod();
}
}


参考

SpringFrameworkのAutowiredでQualifierタグを利用