1概要

この記事では、単体テストのためにSpring BeansにMockitoモックを挿入するための依存性注入の使い方を説明します。

コンポーネントが外部システムへのアクセスに依存することが多い実世界のアプリケーションでは、各テストにクラス階層全体を含めることなく、特定のユニットの機能のテストに集中できるように、適切なテスト分離を提供することが重要です。

モックを注射することはそのような隔離を導入するためのきれいな方法です。


2 Mavenの依存関係

単体テストとモックオブジェクトには、次のMaven依存関係が必要です。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <version>1.3.1.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <version>1.3.1.RELEASE</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>2.21.0</version>
</dependency>

この例ではSpring Bootを使用することにしましたが、従来のSpringでも問題なく動作します。


3テストを書く


3.1. ビジネスロジック

まず、テストするビジネスロジックを書きます。

@Service
public class NameService {
    public String getUserName(String id) {
        return "Real user name";
    }
}


NameService

クラスは次の場所に注入されます。

@Service
public class UserService {

    private NameService nameService;

    @Autowired
    public UserService(NameService nameService) {
        this.nameService = nameService;
    }

    public String getUserName(String id) {
        return nameService.getUserName(id);
    }
}

このチュートリアルでは、指定されたクラスは、提供されたIDに関係なく単一の名前を返します。これは、複雑なロジックをテストしても気が散らないようにするためです。

また、Beanをスキャンしてアプリケーションを初期化するための標準のSpring Bootメインクラスも必要になります。

@SpringBootApplication
public class MocksApplication {
    public static void main(String[]args) {
        SpringApplication.run(MocksApplication.class, args);
    }
}


3.2. テスト

それではテストロジックに移りましょう。まず最初に、テスト用にアプリケーションコンテキストを設定する必要があります。

@Profile("test")
@Configuration
public class NameServiceTestConfiguration {
    @Bean
    @Primary
    public NameService nameService() {
        return Mockito.mock(NameService.class);
    }
}


@ Profile

アノテーションは、「test」プロファイルがアクティブなときにのみこの設定を適用するようにSpringに指示します。

@ Primary

アノテーションは、このインスタンスが自動配線用の実際のインスタンスの代わりに使用されるようにするためのものです。

メソッド自体は、私たちの

NameService

クラスのMockitoモックを作成して返します。

これで単体テストを書くことができます。

@ActiveProfiles("test")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MocksApplication.class)
public class UserServiceTest {

    @Autowired
    private UserService userService;

    @Autowired
    private NameService nameService;

    @Test
    public void whenUserIdIsProvided__thenRetrievedNameIsCorrect() {
        Mockito.when(nameService.getUserName("SomeId")).thenReturn("Mock user name");
        String testName = userService.getUserName("SomeId");
        Assert.assertEquals("Mock user name", testName);
    }
}

私たちは

@ ActiveProfiles

アノテーションを使って“ test”プロファイルを有効にし、先ほど書いたモック設定を有効にします。このため、Springは

UserService

クラスの実際のインスタンスを自動的に配線しますが、

NameService

クラスのモックを配線します。テスト自体はかなり典型的なJUnit + Mockitoテストです。モックの目的の動作を設定してから、テストしたいメソッドを呼び出し、期待した値が返されることを表明します。

このようなテストで環境プロファイルを使用しないようにすることもできます(ただしお勧めしません)。これを行うには、

@ Profileアノテーションと@ActiveProfiles

アノテーションを削除し、

UserServiceTest

クラスに

@ ContextConfiguration(classes = NameServiceTestConfiguration.class)

アノテーションを追加します。


4結論

チュートリアルでは、MockitoモックをSpring Beansにインジェクトする方法を示しました。実装はhttps://github.com/eugenp/tutorials/tree/master/spring-mockito[example GitHub project]にあります。