私のSpring-Bootアプリでは、@ Configurationファイルを使用してRestTemplateを提供しているため、適切なデフォルト(タイムアウトなど)を追加できます。統合テストでは、外部サービスに接続したくないので、RestTemplateをモックしたいと思います-どのような応答が期待されるかはわかっています。後者が実際の実装をオーバーライドすることを期待して、統合テストパッケージに別の実装を提供しようとしましたが、ログを確認することは逆です:実際の実装はテスト実装をオーバーライドします。
TestConfigからのものが使用されていることを確認するにはどうすればよいですか?
これは私の設定ファイルです:
@Configuration
public class RestTemplateProvider {
private static final int DEFAULT_SERVICE_TIMEOUT = 5_000;
@Bean
public RestTemplate restTemplate(){
return new RestTemplate(buildClientConfigurationFactory());
}
private ClientHttpRequestFactory buildClientConfigurationFactory() {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setReadTimeout(DEFAULT_SERVICE_TIMEOUT);
factory.setConnectTimeout(DEFAULT_SERVICE_TIMEOUT);
return factory;
}
}
統合テスト:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestConfiguration.class)
@WebAppConfiguration
@ActiveProfiles("it")
public abstract class IntegrationTest {}
TestConfigurationクラス:
@Configuration
@Import({Application.class, MockRestTemplateConfiguration.class})
public class TestConfiguration {}
そして最後にMockRestTemplateConfiguration
@Configuration
public class MockRestTemplateConfiguration {
@Bean
public RestTemplate restTemplate() {
return Mockito.mock(RestTemplate.class)
}
}
Spring Boot 1.4.x以降、_@MockBean
_注釈を使用してSpring Beanを偽造するオプションがあります。
コメントに対する反応:
コンテキストをキャッシュに保持するには、_@DirtiesContext
_を使用せず、@ContextConfiguration(name = "contextWithFakeBean")
を使用します。個別のコンテキストが作成されますが、デフォルトのコンテキストはキャッシュに保持されます。 Springは両方(またはコンテキストの数)をキャッシュに保持します。
ビルドはこのように行われ、ほとんどのテストではデフォルトの非汚染構成が使用されますが、Beanを偽造するテストは4〜5個あります。デフォルトのコンテキストはうまく再利用されます
1. @Primary
アノテーションを使用できます:
@Configuration
public class MockRestTemplateConfiguration {
@Bean
@Primary
public RestTemplate restTemplate() {
return Mockito.mock(RestTemplate.class)
}
}
ところで、私は Spring Beanの偽造に関するブログ記事 を書きました。
2.しかし、 Spring RestTemplateテストのサポート をご覧になることをお勧めします。これは簡単な例です:private MockRestServiceServer mockServer;
@Autowired
private RestTemplate restTemplate;
@Autowired
private UsersClient usersClient;
@BeforeMethod
public void init() {
mockServer = MockRestServiceServer.createServer(restTemplate);
}
@Test
public void testSingleGet() throws Exception {
// GIVEN
int testingIdentifier = 0;
mockServer.expect(requestTo(USERS_URL + "/" + testingIdentifier))
.andExpect(method(HttpMethod.GET))
.andRespond(withSuccess(TEST_RECORD0, MediaType.APPLICATION_JSON));
// WHEN
User user = usersClient.getUser(testingIdentifier);
// THEN
mockServer.verify();
assertEquals(user.getName(), USER0_NAME);
assertEquals(user.getEmail(), USER0_EMAIL);
}
より多くの例は 私のGithubレポはこちら にあります。
もう少し深く、2番目の答えを参照。
を使用して問題を解決しました
_@SpringBootTest(classes = {AppConfiguration.class, AppTestConfiguration.class})
_
の代わりに
_@Import({ AppConfiguration.class, AppTestConfiguration.class });
_
私の場合、テストはアプリと同じパッケージに入っていません。そのため、明示的にAppConfiguration.class(またはApp.class)を指定する必要があります。テストで同じパッケージを使用する場合、私はあなたが書くことができると思うよりも
_@SpringBootTest(classes = AppTestConfiguration.class)
_
代わりに(動作していません)
_@Import(AppTestConfiguration.class );
_
これが非常に異なることを確認するために結構結構です。これを説明できる人がいるかもしれません。今まで良い答えが見つかりませんでした。 _@SpringBootTests
_が存在する場合、@Import(...)
は選択されないと思うかもしれませんが、ログにオーバーライドするBeanが表示されます。しかし、間違った方法です。
ちなみに、_@TestConfiguration
_の代わりに_@Configuration
_を使用しても違いはありません。
構成の問題は、テスト構成に@Configuration
を使用していることです。これにより、メイン構成が置き換えられます。代わりに、@TestConfiguration
を使用して、メイン構成を追加(上書き)します。
プライマリ設定をカスタマイズする場合は、ネストされた@TestConfigurationクラスを使用できます。アプリケーションのプライマリ設定の代わりに使用されるネストされた@Configurationクラスとは異なり、ネストされた@TestConfigurationクラスはアプリケーションのプライマリ設定に加えて使用されます。
SpringBootを使用した例:
メインクラス
@SpringBootApplication() // Will scan for @Components and @Configs in package tree
public class Main{
}
メイン設定
@Configuration
public void AppConfig() {
// Define any beans
}
テスト構成
@TestConfiguration
public void AppTestConfig(){
// override beans for testing
}
テストクラス
@RunWith(SpringRunner.class)
@Import(AppTestConfig.class)
@SpringBootTest
public void AppTest() {
// use @MockBean if you like
}
注:オーバーライドするBeanを含め、すべてのBeanが作成されることに注意してください。 @Profile
をインスタンス化しない場合は、@Configuration
を使用します。
this answerをそのスレッドで提供されている他の項目と一緒にチェックします。 Spring Boot 2.XでBeanをオーバーライドします。このオプションはデフォルトで無効になっています。また、そのパスを取ることにした場合のBean Definition DSLの使用方法についてのアイデアもあります。
@MockBean
とOPが使用するBeanオーバーライドは、2つの補完的なアプローチです。
@MockBean
を使用してモックを作成し、実際の実装を忘れます。一般的に、テストしているクラスが依存しているBeanこれらのBeanを統合でテストしたくない。
Springはデフォルトでそれらをnull
にしますが、テストを実行するためにそれらの最小限の動作をモックします。
@WebMvcTest
は、レイヤー全体をテストしたくないため、この戦略を非常に頻繁に必要とします。また、@SpringBootTest
は、テスト構成でBean構成のサブセットのみを指定する場合も必要になる場合があります。
一方、可能な限り多くの実際のコンポーネントで統合テストを実行したい場合があります。そのため、@MockBean
を使用したくないが、動作、依存関係を少しオーバーライドしたい、または新しいスコープを定義したいBeanの場合、この場合、従うアプローチはBeanのオーバーライドです。
@SpringBootTest({"spring.main.allow-bean-definition-overriding=true"})
@Import(FooTest.OverrideBean.class)
public class FooTest{
@Test
public void getFoo() throws Exception {
// ...
}
@TestConfiguration
public static class OverrideBean {
// change the bean scope to SINGLETON
@Bean
@Scope(ConfigurableBeanFactory.SINGLETON)
public Bar bar() {
return new Bar();
}
// use a stub for a bean
@Bean
public FooBar BarFoo() {
return new BarFooStub();
}
// use a stub for the dependency of a bean
@Bean
public FooBar fooBar() {
return new FooBar(new StubDependency());
}
}
}