2016-03-02 50 views
6

Dla mojej aplikacji Spring-Boot udostępniam szablon RestTemplate, ale plik @Configuration, dzięki czemu mogę dodawać rozsądne wartości domyślne (np. Timeout). Dla moich testów integracyjnych chciałbym wyśmiewać się z RestTemplate, ponieważ nie chcę łączyć się z usługami zewnętrznymi - wiem, jakich reakcji oczekiwać. Próbowałem dostarczyć inną implementację w pakiecie testu integracji w nadziei, że ta ostatnia zastąpi prawdziwą implementację, ale sprawdzenie dzienników jest odwrotne: prawdziwa implementacja zastępuje testową.

Jak mogę się upewnić, że ten z TestConfig jest używany?Przesłanianie fasoli w testach integracji

To jest mój plik konfiguracyjny: test

@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; 
    } 
} 

Integracja:

@RunWith(SpringJUnit4ClassRunner.class) 
@SpringApplicationConfiguration(classes = TestConfiguration.class) 
@WebAppConfiguration 
@ActiveProfiles("it") 
public abstract class IntegrationTest {} 

klasa TestConfiguration:

@Configuration 
@Import({Application.class, MockRestTemplateConfiguration.class}) 
public class TestConfiguration {} 

I wreszcie MockRestTemplateConfiguration

@Configuration 
public class MockRestTemplateConfiguration { 

    @Bean 
    public RestTemplate restTemplate() { 
     return Mockito.mock(RestTemplate.class) 
    } 
} 
+0

Zmienia kolejność importów, są one przetwarzane w taki sposób, aby były odczytywane, więc nowsze zastępują poprzednie. –

+0

Wypróbowałem ... to samo. Zaktualizuję moje pytanie, aby odzwierciedlić zmiany – mvlupan

+0

Możliwy duplikat [Zastąpienie automatycznie wykopanego ziarna w testach jednostkowych] (https://stackoverflow.com/questions/28605833/overriding-an-autowired-bean-in-unit-tests) – LoganMzz

Odpowiedz

8

od wiosny Boot 1.4.x istnieje możliwość korzystania @MockBean adnotacji do fałszywych Wiosna fasoli.

Reakcja na komentarz:

Aby zachować kontekst w pamięci podręcznej nie używać @DirtiesContext, ale używać @ContextConfiguration(name = "contextWithFakeBean") i stworzy oddzielny kontekst, gdy będzie ona zachować domyślny kontekst w pamięci podręcznej. Spring będzie przechowywać oba (lub ilość kontekstów) w pamięci podręcznej.

Nasza kompilacja jest w ten sposób, w której większość testów korzysta z domyślnej, nieuczciwej konfiguracji, ale mamy 4-5 testów, które podrabiają fasolę. Kontekst domyślny jest ładnie ponownie używany

+0

zgadzają się, że jest to sposób postępowania w większości przypadków. Minusem, który znalazłem przy takim podejściu jest to, że utracisz korzyści z buforowania kontekstu w następnej klasie testowej. Aby nasze testy integracji były tak szybkie, jak to możliwe, rozszerzamy jedną klasę, gdy tylko jest to możliwe. – mvlupan

+0

prawda, ale czasami nie ma innej drogi. Na przykład. kiedy trzeba sfałszować usługi zewnętrzne. – luboskrnac

+0

Zaktualizowałem swoją odpowiedź za pomocą kontekstowej sztuczki buforowania. – luboskrnac

6

1. Można użyć @Primary adnotacji:

@Configuration 
public class MockRestTemplateConfiguration { 

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

BTW, pisałem blog post about faking Spring bean

2. Ale proponuję przyjrzeć Spring RestTemplate testing support. To byłby prosty przykład: prywatny 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); 
    } 

Więcej przykładów można znaleźć w my Github repo here

+0

Wypróbowałem drugą sugestię i działa świetnie. Dzięki za podpowiedź .. Czuję, że jest to "poprawna" droga. – mvlupan