Giriş
Şu satırı dahil ederiz
Şu satırı dahil ederiz
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
Not : Bu anotasyon yerine gerçek veri tabanında test için @AutoConfigureTestDatabase tercih edilebilir.
Kullanım Amacı
1. Repository sınıflarının test edilmesi
2. Service sınıflarının test edilmesi
@DataJpaTest Anotasyonu Ne Yapar?
@WebMvcTest Anotasyonu gibi sadece bazı bean'leri yükler. Açıklaması şöyle. Dolayısıyla @SpringBootTest anotasyonunu kullanmaya gerek kalmaz.
The @DataJpaTest annotation will only provide the autoconfiguration required to test Spring Data JPA using an in-memory database such as H2.
This annotation is used instead of @SpringBootTest.
Bu anotasyonla bellekte bir veri tabanı oluşturulur. Açıklaması şöyle
By default, tests annotated with @DataJpaTest will use an embedded in-memory database (replacing any explicit or usually auto-configured DataSource).
java.lang.IllegalStateException : Failed to replace DataSource with an embedded database for tests. If you want an embedded database please put a supported one the classpath or tune the replace attribute of @AutoConfigurationTestDatabaseVeri tabanının Oluşturulması
Test Suite çalışınca bir kere bellekte yeni bir veri tabanı oluşturulur. Bunun çıktısı olarak Spring logusu görülebilir. Daha sonra her test sadece en başta yaratılmış olan bellekteki veri tabanına CRUD işlemi yapar.
Transaction
Açıklaması şöyle
By default, @DataJpaTest tests are transactional and roll back at the end of each test.
Örnek
Rollback işlemi olmasın diye @Commit kullanılabilir. Şöyle yaparız
import org.springframework.test.annotation.Commit; @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @DataJpaTest(showSql = true) class FooRepositoryTest { @Autowired private FooRepository repository; @Test @Order(1) @Commit void autoGenerateId() { FooEntity entity = new FooEntity(); entity.setInstant(Instant.ofEpochMilli(0)); repository.save(entity); assertEquals(entity.getId(), 1); } @Test @Order(2) void findById() { List<FooEntity> all = repository.findAll(); assertFalse(all.isEmpty()); FooEntity entity = all.get(0); assertEquals(entity.getInstant(), Instant.ofEpochMilli(0)); } }
Repository Sınıflarının Test Edilmesi
1. TestEntityManager Inject Edilmesini Sağlar
Açıklaması şöyle.
Using this annotation we can have a TestEntityManager injected on the test, and use it to change the database to a state in which it's possible to unit test our repository methods.Test kodu içinde TestEntityManager @AutoWire edilebilir.
2. Repository Sınıflarının Inject Edilmesini Sağlar
Örnek
Şöyle yaparız
@DataJpaTestclass PersonRepositoryDataJpaTest {@Autowiredprivate PersonRepository personRepository;@Testvoid shouldReturnAllLastNames() {personRepository.saveAndFlush(new Person().setFirstName("John").setLastName("Brown"));personRepository.saveAndFlush(new Person().setFirstName("Kyle").setLastName("Green"));personRepository.saveAndFlush(new Person().setFirstName("Paul").setLastName("Brown"));assertEquals(Set.of("Brown", "Green"), personRepository.findAllLastNames());}}
Örnek
Şöyle yaparız. Burada respository kullanılarak kaydedilen nesneye ID atandığı test ediliyor.
@DataJpaTest class WebAuthnUserRepositoryTest { @Autowired WebAuthnUserRepository userRepository; @Test public void test() { WebAuthnUser user = new WebAuthnUser(); user.setUsername("junit"); userRepository.save(user); assertNotNull(user.getId()); } }
Örnek
Tam çalışan bir örnek şöyle
@DataJpaTest @ExtendWith(SpringExtension.class) @AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.H2) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class OrderRepositoryUnitTest { @Autowired OrderRepository orderRepository; @BeforeEach public void setUp() { orderRepository.save(new Order(100L, "jane", 200.0, 2)); orderRepository.save(new Order(200L, "ben", 100.0, 5)); } @AfterEach public void destroy() { orderRepository.deleteAll(); } @Test public void testGetAllOrders() { List<Order> orderList = orderRepository.findAll(); Assertions.assertThat(orderList.size()).isEqualTo(2); Assertions.assertThat(orderList.get(0).getId()).isNotNegative(); Assertions.assertThat(orderList.get(0).getId()).isGreaterThan(0); Assertions.assertThat(orderList.get(0).getBuyer()).isEqualTo("jane"); } @Test public void testGetInvalidOrder() { Exception exception = assertThrows(NoSuchElementException.class, () -> { orderRepository.findById(120L).get(); }); Assertions.assertThat(exception).isNotNull(); Assertions.assertThat(exception.getClass()).isEqualTo(NoSuchElementException.class); Assertions.assertThat(exception.getMessage()).isEqualTo("No value present"); } @Test public void testGetCreateOrder() { Order saved = new Order(300L, "tim", 50.0, 4); Order returned = orderRepository.save(saved); Assertions.assertThat(returned).isNotNull(); Assertions.assertThat(returned.getBuyer()).isNotEmpty(); Assertions.assertThat(returned.getId()).isGreaterThan(1); Assertions.assertThat(returned.getId()).isNotNegative(); Assertions.assertThat(saved.getBuyer()).isEqualTo(returned.getBuyer()); } @Test public void testDeleteOrder() { Order saved = new Order(400L, "ron", 60.0, 3); orderRepository.save(saved); orderRepository.delete(saved); Exception exception = assertThrows(NoSuchElementException.class, () -> { orderRepository.findById(400L).get(); }); Assertions.assertThat(exception).isNotNull(); Assertions.assertThat(exception.getClass()).isEqualTo(NoSuchElementException.class); Assertions.assertThat(exception.getMessage()).isEqualTo("No value present"); } }
Örnek
@RunWith( SpringRunner.class )
@DataJpaTest
@ContextConfiguration(classes=PersistenceConfig.class)
public class PersonRepositoryTest {
// Tests ...
}
Service Sınıflarının Test Edilmesi - KullanmayınAçıklaması şöyle
... you can use @DataJpaTest annotation that starts JPA components and Repository beans. and use @Import annotation to load the service class itself.
Ancak bu kullanım şeklinde dikkatli olmak lazım, çünkü tüm test tek bir transaction ile çalışıyor. Açıklaması şöyle
@DataJpaTest wraps the suite with the @Transactional. So, the test suite and the service are both transactional. The default propagation level for the annotation is REQUIRED. It means that calling another transactional method does not start a new transaction. Instead, it continues to execute SQL statements in the current one.
Örnek
Şöyle yaparız. Burada hem Service sınıfının yüklenmesi sağlanıyor, hem de @AutoConfigureTestDatabase ile gerçek veri tabanı kullanılıyor
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabaseimport org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace
.ANYimport org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTestimport org.springframework.context.annotation.ComponentScanimport org.springframework.context.annotation.FilterType.ASSIGNABLE_TYPE@DataJpaTest(includeFilters = [ComponentScan.Filter(ViewersService::class, type = ASSIGNABLE_TYPE)])@AutoConfigureTestDatabase(replace = ANY)internal class ViewersServiceIntegrationTest {@Autowiredprivate lateinit var viewersService: ViewersService@Autowiredprivate lateinit var viewersRepository: ViewersRepository...}
Örnek
Şöyle yaparız
@DataJpaTest(showSql = false)@Import(TestService.class)public class ServiceTest {@Autowiredprivate TestService service;@Testvoid testFindAll() {List<String> values = service.findAll();assertEquals(1, values.size());}}
Örnek
Test koşmaya başlayınca otomatik Transaction'ı başlatmamak için şöyle yaparız
@DataJpaTest@Transactional(propagation = Propagation.NOT_SUPPORTED)class PersonCreateServiceImplTestH2 {@Autowiredprivate PersonRepository personRepository;@MockBeanprivate PersonValidateService personValidateService;@Autowiredprivate PersonCreateService personCreateService;@BeforeEachvoid beforeEach() {personRepository.deleteAll();}@TestConfigurationstatic class Config {@Beanpublic PersonCreateService personCreateService(PersonRepository personRepository,PersonValidateService personValidateService) {return new PersonCreateServiceImpl(personValidateService, personRepository);}}// test cases...}
Dolayısıyla artık bu test servis kodu exception fırlatınca geçmeye başlar.
@Testvoid shouldRollbackIfAnyUserIsNotValidated() {doThrow(new ValidationFailedException("")).when(personValidateService).checkUserCreation("John", "Brown");assertThrows(ValidationFailedException.class, () -> personCreateService.createFamily(List.of("Matilda", "Vasya", "John"),"Brown"));assertEquals(0, personRepository.count());}
@DataJpaTest Anotasyonu Alternatifi
Örnek
Hem tüm projeyi yüklemek, hem de H2 veri tabanı yaratmak için şöyle yaparız. @AutoConfigureTestDatabase otomatik olarak bir veri tabanı yaratır
@SpringBootTest(webEnvironment = WebEnvironment.NONE)@AutoConfigureTestDatabaseclass PersonCreateServiceImplSpringBootTest {@Autowiredprivate PersonRepository personRepository;@MockBeanprivate PersonValidateService personValidateService;@Autowiredprivate PersonCreateService personCreateService;@BeforeEachvoid init() {personRepository.deleteAll();}}
Hiç yorum yok:
Yorum Gönder