web-dev-qa-db-ja.com

アプリケーションを開始する前に@MockBeanコンポーネントを構成する

Spring Boot 1.4.2アプリケーションがあります。起動時に使用されるいくつかのコードは次のようになります:

_@Component 
class SystemTypeDetector{
    public enum SystemType{ TYPE_A, TYPE_B, TYPE_C }
    public SystemType getSystemType(){ return ... }
}

@Component 
public class SomeOtherComponent{
    @Autowired 
    private SystemTypeDetector systemTypeDetector;
    @PostConstruct 
    public void startup(){
        switch(systemTypeDetector.getSystemType()){   // <-- NPE here in test
        case TYPE_A: ...
        case TYPE_B: ...
        case TYPE_C: ...
        }
    }
}
_

システムタイプを決定するコンポーネントがあります。このコンポーネントは、他のコンポーネントからの起動時に使用されます。本番環境では、すべてが正常に機能します。

ここで、Spring 1.4の_@MockBean_を使用して、いくつかの統合テストを追加したいと思います。

テストは次のようになります。

_@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyWebApplication.class, webEnvironment = RANDOM_PORT)
public class IntegrationTestNrOne {
    @MockBean 
    private SystemTypeDetector systemTypeDetectorMock;

    @Before 
    public void initMock(){
       Mockito.when(systemTypeDetectorMock.getSystemType()).thenReturn(TYPE_C);
    }

    @Test 
    public void testNrOne(){
      // ...
    }
}
_

基本的に、モックは正常に機能します。私のsystemTypeDetectorMockが使用され、getSystemTypeを呼び出すと、_TYPE_C_が返されます。

問題は、アプリケーションが起動しないことです。現在、春の作業順序は次のようです:

  1. すべてのモックを作成します(構成なしですべてのメソッドがnullを返します)
  2. アプリケーションを開始
  3. @ Before-methodsを呼び出します(モックが構成されます)。
  4. テストを開始

私の問題は、アプリケーションが初期化されていないモックで始まることです。したがって、getSystemType()の呼び出しはnullを返します。

私の質問は:アプリケーションの起動前にモックbeforeを構成するにはどうすればよいですか?

編集:誰かが同じ問題を抱えている場合、1つの回避策@MockBean(answer = CALLS_REAL_METHODS)を使用することです。これにより実際のコンポーネントが呼び出され、私の場合はシステムが起動します。起動後、モックの動作を変更できます。

24
Marcel

この場合、@MockBeanが導入される前にモックを構成した方法でモックを構成する必要があります。コンテキストで元のBeanを置き換える@Primary Beanを手動で指定します。

@SpringBootTest
class DemoApplicationTests {

    @TestConfiguration
    public static class TestConfig {

        @Bean
        @Primary
        public SystemTypeDetector mockSystemTypeDetector() {
            SystemTypeDetector std = mock(SystemTypeDetector.class);
            when(std.getSystemType()).thenReturn(TYPE_C);
            return std;
        }

    }

    @Autowired
    private SystemTypeDetector systemTypeDetector;

    @Test
    void contextLoads() {
        assertThat(systemTypeDetector.getSystemType()).isEqualTo(TYPE_C);
    }
}

@TestConfigurationクラスは静的内部クラスであるため、このテストでのみ自動的に選択されます。 @Beforeに入れる完全なモック動作は、Beanを初期化するメソッドに移動する必要があります。

7

Uが使用しているものは、単体テストに適しています。

org.mockito.Mockito#when()

コンテキストがスピンアップされているときにSpring Beanをモックするために次のメソッドを使用してみてください。

org.mockito.BDDMockito#given()

@SpyBeanを使用している場合は、別の構文を使用する必要があります。

willReturn(Arrays.asList(val1, val2))
        .given(service).getEntities(any());
0
Niki.Max

Springの初期化は@Before Mockitoのアノテーションの前にトリガーされるため、@PostConstructアノテーション付きメソッドの実行時にモックは初期化されません。

SystemTypeDetectorコンポーネントの@Lazyアノテーションを使用して、システム検出を「遅延」してみてください。 SystemTypeDetectorは必要な場所で使用してください。@PostConstructまたは同等のフックでこの検出をトリガーすることはできないことに注意してください。

0
Florian Lopes