GirişŞu satırı dahil ederiz
import org.springframework.boot.test.context.SpringBootTest;
spring-boot-test-starter (in the test scope) contains Junit5、Mockito、 Spring Testlibraries and we find these common libraries to be useful when writing tests.
Spring ile integration test yapmayı sağlayan anotasyonlardan birisidir. Bu anotasyon unit test için değildir, çünkü eğer özel bir ayar yapmadıysak tüm application context'i ayağa kaldırır. Yani tüm uygulama çalışır. Eğer uygulamamızdaki bazı katmanları test etmek istiyorsak Test Slices başlığı altında geçen, ve daha kısıtlı bir application context yaratılmasını sağlayan diğer anotasyonları kullanmak gerekir.
Eğer amacımız integration test değilse
Eğer amacımız integration test değilse :
- Tüm application context yerine @ContextConfiguration anotasyonu ile teste kullanılacak bean'leri yaratabiliriz.
- @TestConfiguration anotasyonu ile testte kullanılacak bean'leri
yaratabiliriz- Basit JUnit kullanılabilir.
- Mockito ile mock kullanabiliriz
Mockito Kullanma
Örnek - JUnit5
@ExtendWith(MockitoExtension.class)
public class ProductManagerTest {
@InjectMocks
private ProductManager productManager;
@Mock
private ProductDAO productDAO;
@Test
public void givenProduct_whenCreate_thenReturnProduct() {
}
}
Örnek - JUnit4
Elimizde şöyle bir kod olsun
@Service
public class Demo{
@Autowired
private Demo1 demo1;
public Boolean doInvoke() {
//do something
}
}
@SpringBootTest(classes=Demo.class)
public class demoTest{
@Autowired
private Demo demo;
@MockBean
private Demo1 demo1;
@Test
public void test() {
BDDMockito.given(demo1.test).willReturn(true);
Boolean result = demo.doInvoke();
Assertions.assertTrue(result);
}
}
Burada @SpringBootTest kullanmaya gerek yok. Şöyle
yaparız@RunWith(MockitoJUnitRunner.class)
public class DemoTest{
@Mock
private Demo1 demo1;
@InjectMocks
private Demo demo;
@Test
public void test() {
BDDMockito.given(demo1.test).willReturn(true);
Boolean result = demo.doInvoke();
Assertions.assertTrue(result);
}
}
Eğer amacımız integration test ise
- Customization için @SpringBootTest anotasyonunun properties alanı
kullanılabilir.
- @ActiveProfiles anotasyonu kullanılabilir. Böylece belirtilen
application-<profile>.properties veya
application-<profile>.yml dosyaları
kullanılır- @MockBean anotasyonu ile gerçek bean yerine mock bir bean kullanabiliriz
- @TestConfiguration anotasyonu ile uygulamadaki bean'lere ilave olarak yeni bir test bean'i yaratabiliriz ,veya bir bean'i override edebiliriz.
- @Configuration anotasyon ile teste mahsus bir primary configuration
yaratabiliriz.
- @SpringBootTest anotasyonunun classes alanı kullanılarak application context içinde hangi sınıfların olacağı
belirtilir.
@SpringBootTest Ne Yapar
Test sınıfının bulunduğu paketten başlayarak yukarı doğru çıkar ve @SpringBootConfiguration anotasyonunu arar. Bu anotasyonu ayrı olarak tanımlamadıysak @SpringBootApplication yani main sınıfımız bu anotasyonu sağlar.
ApplicationContext Cache'lenmesi
Starting a Spring context for your test takes a good amount of time. Especially if you populate the whole context using @SpringBootTest. This adds an additional overhead (time-wise) to your test execution and may drastically increase your total build time.
Fortunately, Spring Test provides a mechanism to cache an already started application context and reuse it for subsequent tests. You can think of a basic Map that stores different application contexts. Spring Test creates a uniquely identifiable key for the Map entry.
Açıklaması
şöyle.
Spring Boot provides a @SpringBootTest annotation which can be used as an alternative to the standard spring-test @ContextConfiguration annotation when you need Spring Boot features. The annotation works by creating the ApplicationContext used in your tests via SpringApplication. The Spring TestContext framework stores application contexts in a static cache. This means that the context is literally stored in a static variable. In other words, if tests execute in separate processes the static cache will be cleared between each test execution, and this will effectively disable the caching mechanism. To benefit from the caching mechanism, all tests must run within the same process or test suite. This can be achieved by executing all tests as a group within an IDE
Açıklaması
şöyle.
By default, once loaded, the configured ApplicationContext is reused for each test. Thus the setup cost is incurred only once per test suite, and subsequent test execution is much faster. In this context, the term test suite means all tests run in the same JVM
ApplicationContext Cache'lenmesini Engelleyen Şeyler
Eğer testte @Autowired varsa sorun
yok.
Ama testlerdeki bazı anotasyonlar cache'i kullanmayı engelliyor. Bu da testlerin yavaş çalışmasına sebep olur. Açıklaması
şöyle. Bunlardan en problemli olanlar
@MockBean ve @SpyBean
By reading these articles and the same ones, I realized that there are some pitfalls in integration tests that prevent the Spring from reusing the loaded application context in integration tests. Here are the most important ones:
- Using @MockBean and @SpyBean
- Using @DirtiesContext
- Careless use of profiles in integration tests
- Careless use of @TestPropertySource
MockMvc Inject Edilmesi
Eğer gerçek bir web sunucusu kullanmıyorsak, tüm application context'i ayağa kaldırıdıp MockMvc kullanmak mümkün. Burada @AutoConfigureMockMvc ile bir adet MockMvc autowire ediliyor.
Örnek
@ExtendWith(SpringExtension.class)
@SpringBootTest
@AutoConfigureMockMvc
class RegisterUseCaseIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private UserRepository userRepository;
@Test
void registrationWorksThroughAllLayers() throws Exception {
UserResource user = new UserResource("Zaphod", "zaphod@galaxy.net");
mockMvc.perform(post("/forums/{forumId}/register", 42L)
.contentType("application/json")
.param("sendWelcomeMail", "true")
.content(objectMapper.writeValueAsString(user)))
.andExpect(status().isOk());
UserEntity userEntity = userRepository.findByName("Zaphod");
assertThat(userEntity.getEmail()).isEqualTo("zaphod@galaxy.net");
}
}
TestRestTemplate Inject Edilmesi
classes Alanı
classes Alanı yazısına taşıdım
webEnvironment Alanı
Açıklaması
şöyle. Eğer bu alanı tanımlarsak bir tane web sunucusu yaratılır.
By default, @SpringBootTest will not start a server. You can use the webEnvironment attribute of @SpringBootTest to further refine how your tests run:
Sunucuyu değişik modlarda başlatmak mümkün. Açıklaması
şöyle.
This annotation configures a complete test environment with all your beans and everything set up. You can choose to start a mock servlet environment, or even start a real one with the webEnvironment attribute of the @SpringBootTest annotation.
Şu değerleri alabilir.
MOCK
RANDOM_PORT
DEFINED_PORT
NONE
DEFINED_PORT DeğeriGerçek bir servlet ortamı başlatır.
RANDOM_PORT Değeri
Açıklaması
şöyle. Gerçek bir servlet ortamı başlatır.
Loads a WebServerApplicationContext and provides a real web environment. Embedded servers are started and listen on a random port.
Örnek
Şöyle yaparız
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)