JUnit ile Servis Katmanı Testi-3
ArgumentCaptor kullanarak nasıl unit test yazabiliriz konusuna değineceğiz.
Öncelikle okumadıysanız eğer önceki yazıları da okumanızda fayda var.
Bu yazıda ArgumentCaptur kullanarak testlerimize yeni özellikler eklemeye çalışacağız. Servis katmanını tekrar hatırlayalım.
Service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
@Service public class RealtyService { private static final int MAX_INDIVICUAL_REALTY_SIZE = 5; @Autowired private UserService userService; @Autowired private RealtyRepository realtyRepository; @Autowired private BannerServiceClient bannerServiceClient; private Logger logger = Logger.getLogger(RealtyService.class.getName()); public Realty create(RealtyRequest realtyRequest) { User foundUser = userService.getById(realtyRequest.getUserId()) .orElseThrow(() -> new UserNotFoundException("kullanıcı bulunamadı")); if (UserType.INDIVIDUAL.equals(foundUser.getType())) { validateIndividualRealtySize(foundUser); } Realty realty = convert(realtyRequest, foundUser); Banner bannerRequest = new Banner(String.valueOf(realty.getNo()), 1, "123123", "banner açıklaması"); BannerResponse bannerResponse = bannerServiceClient.create(bannerRequest); if (!HttpStatus.CREATED.equals(bannerResponse.getHttpStatus())) { logger.log(Level.WARNING, "Banner kaydedilemedi!"); throw new RuntimeException("Banner kaydedilemedi!"); } return realtyRepository.save(realty); } private void validateIndividualRealtySize(User foundUser) { List<Realty> realtyList = realtyRepository.findAllByUserId(foundUser.getId()); if (MAX_INDIVICUAL_REALTY_SIZE < realtyList.size()) { logger.log(Level.INFO, "Bireysel kullanıcı en fazla 5 ilan girebilir. userID : {0}", foundUser.getId()); throw new EmlakCepteException("Bireysel kullanıcı en fazla 5 ilan girebilir"); } } private Realty convert(RealtyRequest realtyRequest, User foundUser) { Realty realty = new Realty(); realty.setNo(realtyRequest.getNo()); realty.setCreateDate(LocalDateTime.now()); realty.setStatus(RealtyType.ACTIVE); realty.setTitle(realtyRequest.getTitle()); realty.setProvince(realtyRequest.getProvince()); realty.setUser(foundUser); return realty; } } |
Unit Test
Tek bir method üzerinden örnekleme yapacağım önceki yazıda yaptığımız methodlarda siz de gerekli refactor işlemlerini gerçekleştirebilirsiniz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
@ExtendWith(SpringExtension.class) class RealtyServiceTest { @InjectMocks private RealtyService realtyService; @Mock private UserService userService; @Mock private RealtyRepository realtyRepository; @Mock private BannerServiceClient bannerServiceClient; @Captor private ArgumentCaptor<Realty> realtyCaptor; @Test void it_should_save_realty() { // given ArgumentCaptor<Realty> captor = ArgumentCaptor.forClass(Realty.class); Optional<User> user = getUser(1, UserType.INDIVIDUAL); Mockito.when(userService.getById(1)).thenReturn(user); Mockito.when(realtyRepository.findAllByUserId(1)).thenReturn(getRealtyList(4)); Mockito.when(bannerServiceClient.create(Mockito.any(Banner.class))) .thenReturn(getBannerResponse(HttpStatus.CREATED)); Realty realty = getRealty(1); Mockito.when(realtyRepository.save(Mockito.any())).thenReturn(realty); // when Realty responseRealty = realtyService.create(getRealtyRequest(1)); // then verify(realtyRepository, times(1)).save(captor.capture()); Realty captoredRealty = captor.getValue(); assertThat(responseRealty).isNotNull(); assertThat(responseRealty.getId()).isEqualTo(captoredRealty.getId()); assertThat(responseRealty.getTitle()).isEqualTo(captoredRealty.getTitle()); assertThat(responseRealty.getProvince()).isEqualTo(captoredRealty.getProvince()); assertThat(responseRealty.getStatus()).isEqualTo(captoredRealty.getStatus()); } } |
Not: verify kısmında önceki yazılarda olan kısımları yeni kodların daha net gözükmesi için eklemedim. Merak edenler önceki yazıdan kontrol edebilir.
Peki neden ArgumentCaptor’a ihtiyacımız var?
Bu sorunun cevabı için bir önceki yazıdan önceki versiyonu hatırlayalım. Aşağıdaki eski versiyonu incelediğimizde ‘save’ işlemi sırasında herhangi bir Realty objesiyle çağrıldığını doğrulmaya çalıştığımızı söylemiştik. Daha sonrasında ise id, title, province, status bilgilerini mockladığımız obje ile karşılaştırmıştık. Buradaki problem zaten kendi oluşturduğumuz objeyi yine kendi oluşturduğumuz obje ile doğrulamaya çalışmamız.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Mockito.verify(realtyRepository, times(1)).save(Mockito.any(Realty.class)); assertThat(responseRealty).isNotNull(); assertThat(responseRealty.getId()).isEqualTo(realty.getId()); assertThat(responseRealty.getTitle()).isEqualTo(realty.getTitle()); assertThat(responseRealty.getProvince()).isEqualTo(realty.getProvince()); assertThat(responseRealty.getStatus()).isEqualTo(realty.getStatus()); |
Asıl doğrulamamız gereken ise kod içerisinde bu objenin bir değişikliğe uğrayıp uğramadığıdır.
Hemen bunu anlatmaya çalıştığım sorunu örnekleyelim.
Yukarıdaki convert methodunu aşağıdaki gibi değiştireceğim.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
private Realty convert(RealtyRequest realtyRequest, User foundUser) { Realty realty = new Realty(); realty.setNo(realtyRequest.getNo()); realty.setCreateDate(LocalDateTime.now()); realty.setStatus(RealtyType.PASSIVE); realty.setTitle(realtyRequest.getTitle()); realty.setProvince(realtyRequest.getProvince()); realty.setUser(foundUser); return realty; } |
Şimdi testi çalıştırıp sonucu görelim.
Test methodumuzun önceki haliyle aynı kodu çalıştırdığımıda ise aşağıdaki gibi testlerin geçtiğini göreceğiz.
Çünkü obje üzerinde manipülasyon oldu ve biz bu kaçırdık.
Nasıl Kullanabiliriz?
Aşağıdaki gibi iki şekilde de tanımlayıp kullanabilirsiniz.
1 2 3 4 5 6 7 8 |
@Captor private ArgumentCaptor<Realty> realtyCaptor; // birinci kullanım ArgumentCaptor<Realty> captor = ArgumentCaptor.forClass(Realty.class); // ikinci kullanım |
Görüldüğü üzere verify() methodu ile beraber kullanılıyor.
1 2 3 4 5 6 7 |
verify(realtyRepository, times(1)).save(captor.capture()); Realty captoredRealty = captor.getValue(); |
Veriyi yakaladıktan(capture) sonra artık yukarıdaki gibi doğrulama işlemleri için kullanabilirsiniz.
Faydalı olması dileğiyle.