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
_が返されます。
問題は、アプリケーションが起動しないことです。現在、春の作業順序は次のようです:
私の問題は、アプリケーションが初期化されていないモックで始まることです。したがって、getSystemType()
の呼び出しはnullを返します。
私の質問は:アプリケーションの起動前にモックbeforeを構成するにはどうすればよいですか?
編集:誰かが同じ問題を抱えている場合、1つの回避策は@MockBean(answer = CALLS_REAL_METHODS)
を使用することです。これにより実際のコンポーネントが呼び出され、私の場合はシステムが起動します。起動後、モックの動作を変更できます。
この場合、@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を初期化するメソッドに移動する必要があります。
Uが使用しているものは、単体テストに適しています。
org.mockito.Mockito#when()
コンテキストがスピンアップされているときにSpring Beanをモックするために次のメソッドを使用してみてください。
org.mockito.BDDMockito#given()
@SpyBeanを使用している場合は、別の構文を使用する必要があります。
willReturn(Arrays.asList(val1, val2))
.given(service).getEntities(any());
Springの初期化は@Before
Mockitoのアノテーションの前にトリガーされるため、@PostConstruct
アノテーション付きメソッドの実行時にモックは初期化されません。
SystemTypeDetector
コンポーネントの@Lazy
アノテーションを使用して、システム検出を「遅延」してみてください。 SystemTypeDetector
は必要な場所で使用してください。@PostConstruct
または同等のフックでこの検出をトリガーすることはできないことに注意してください。