복붙노트

[SPRING] 통합 테스트에서 빈 재정의

SPRING

통합 테스트에서 빈 재정의

내 Spring-Boot 응용 프로그램의 경우 @Configuration 파일을 통해 RestTemplate을 제공하므로 합리적인 기본값 (예 : Timeouts)을 추가 할 수 있습니다. 내 통합 테스트를 위해 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)
    }
}

해결법

  1. ==============================

    1.Spring Boot 1.4.x 이후 @MockBean annotation을 사용하여 Spring bean을 위조하는 옵션이있다.

    Spring Boot 1.4.x 이후 @MockBean annotation을 사용하여 Spring bean을 위조하는 옵션이있다.

    댓글에 대한 반응 :

    캐시에 컨텍스트를 유지하려면 @DirtiesContext를 사용하지 말고 @ContextConfiguration (name = "contextWithFakeBean")을 사용하면 별도의 컨텍스트가 만들어지고 캐시에 기본 컨텍스트가 유지됩니다. Spring은 캐시에 둘 다 보유하고있는 컨텍스트를 유지합니다.

    우리의 빌드는 대부분의 테스트가 비 오염 환경 설정을 사용하는 방식이지만, 우리는 가짜 bean 인 4-5 개의 테스트를 가지고 있습니다. 기본 컨텍스트가 멋지게 재사용됩니다.

  2. ==============================

    2.1. @Primary 주석을 사용할 수 있습니다.

    1. @Primary 주석을 사용할 수 있습니다.

    @Configuration
    public class MockRestTemplateConfiguration {
    
        @Bean
        @Primary
        public RestTemplate restTemplate() {
            return Mockito.mock(RestTemplate.class)
        }
    }
    

    BTW, 나는 봄 콩을 가짜에 관한 블로그 포스트를 썼다.

    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 레포에서 더 많은 예제를 찾을 수 있습니다.

  3. ==============================

    3.조금 더 깊이 들어가면 내 두 번째 대답을 참조하십시오.

    조금 더 깊이 들어가면 내 두 번째 대답을 참조하십시오.

    문제를 해결하기 위해

    @SpringBootTest(classes = {AppConfiguration.class, AppTestConfiguration.class})
    

    대신에

    @Import({ AppConfiguration.class, AppTestConfiguration.class });
    

    제 경우에는 테스트가 앱과 같은 패키지에 없습니다. 그래서 명시 적으로 AppConfiguration.class (또는 App.class)를 지정해야합니다. 테스트에서 동일한 패키지를 사용하는 경우

    @SpringBootTest(classes = AppTestConfiguration.class)
    

    대신 (작동하지 않음)

    @Import(AppTestConfiguration.class );
    

    이것이 매우 다른 것을보기에는 꽤 유선입니다. 아마도 이것을 설명 할 수있는 사람이있을 것입니다. 지금까지 좋은 답변을 찾을 수 없었습니다. @SpringBootTestsis가 있으면 @Import (...)가 선택되지 않지만, 무시한 Bean이 로그에 표시됩니다. 그러나 주위에 잘못된 길.

    그런데 @TestConfiguration 대신 @Configuration을 사용하면 아무런 차이가 없습니다.

  4. ==============================

    4.구성의 문제점은 테스트 구성에 @Configuration을 사용하고 있다는 것입니다. 이렇게하면 기본 구성이 바뀝니다. 대신 @TestConfiguration을 사용하여 기본 구성을 추가 (재 지정)하십시오.

    구성의 문제점은 테스트 구성에 @Configuration을 사용하고 있다는 것입니다. 이렇게하면 기본 구성이 바뀝니다. 대신 @TestConfiguration을 사용하여 기본 구성을 추가 (재 지정)하십시오.

    46.3.2 테스트 구성 감지

    스프링 부트 사용 예제 :

    메인 클래스

    @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을 포함하여 생성된다는 점에 유의하십시오. @Configuration을 인스턴스화하지 않으려면 @Profile을 사용하십시오.

  5. ==============================

    5.해당 스레드에서 제공되는 다른 사람들과 함께이 응답을 확인하십시오. 이 옵션은 기본적으로 비활성화되어있는 Spring Boot 2.X의 Bean을 재정의하는 것입니다. Bean Definition DSL을 사용하는 방법에 대한 아이디어도있다.

    해당 스레드에서 제공되는 다른 사람들과 함께이 응답을 확인하십시오. 이 옵션은 기본적으로 비활성화되어있는 Spring Boot 2.X의 Bean을 재정의하는 것입니다. Bean Definition DSL을 사용하는 방법에 대한 아이디어도있다.

  6. from https://stackoverflow.com/questions/35742920/overriding-beans-in-integration-tests by cc-by-sa and MIT license