LoginSignup
7
5

More than 5 years have passed since last update.

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

Last updated at Posted at 2019-02-23

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タグを利用

7
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
5