본문 바로가기

Spring boot

SpringBoot TDD 끄적끄적

반응형

Spring 으로 TDD 개발 할 때....

  • JPA 레퍼지토리를 테스트하기 위해서는 @DataJpaTest 어노테이션을 테스트 클래스에 추가해줘야한다.
  • @DataJpaTest은 기본적으로 H2 DATABASE를 기본으로 한다
  • Repository -> Service -> Controller 순으로 테스트주도개발 하는 것을 추천한다. Repository는 구현할 메서드가 없는 통합테스트에 가깝기 때문에 테스트하기 쉽다. 또 Repository가 안정되면 나머지 계층의 테스트도 안정적으로 작성할 수 있다.

 

Spring 으로 Mockito 라이브러리의 핵심 메소드 !! when, verify

when 메소드

when 메소드는 모킹된 객체의 특정 메소드가 호출될 때 그 메소드의 동작을 정의합니다. 예를 들어,

when(userRepository.save(any(User.class))).thenReturn(user)

는 다음과 같은 의미를 갖습니다:

  • userRepository 객체의 save 메소드가 호출될 때, 인자와 상관없이 항상 user 객체를 반환하도록 설정합니다.
  • any(User.class)는 User 타입의 어떤 객체가 오든 상관없이 동작하도록 설정합니다.

verify 메소드

verify 메소드는 모킹된 객체의 메소드가 특정 횟수만큼 호출되었는지, 또는 특정 인자로 호출되었는지를 검증합니다. 예를 들어,

verify(userRepository, times(1)).findByUsername("testuser")

verify(userRepository, times(1)).findByUsername("testuser")

는 다음과 같은 의미를 갖습니다:

 

  • userRepository 객체의 findByUsername("testuser") 메소드가 정확히 한 번 호출되었는지를 검증합니다.
  • 이 검증은 테스트 메소드가 끝날 때 수행되며, 예상된 호출 횟수와 실제 호출 횟수가 일치하지 않으면 테스트는 실패합니다.

전체 예시 코드

 

// `userRepository`의 `findByUsername` 메소드가 "testuser"를 인자로 받아 호출되면 `null`을 반환하도록 설정
when(userRepository.findByUsername("testuser")).thenReturn(null);

// `userRepository`의 `save` 메소드가 어떤 `User` 객체를 인자로 받아 호출되면 `user` 객체를 반환하도록 설정
when(userRepository.save(any(User.class))).thenReturn(user);

// `userService`의 `registerUser` 메소드를 호출하여 사용자 등록을 시도
User registeredUser = userService.registerUser(user);

// 등록된 사용자가 `null`이 아닌지 검증
assertNotNull(registeredUser);

// 등록된 사용자의 이름이 "testuser"인지 검증
assertEquals("testuser", registeredUser.getUsername());

// `userRepository`의 `findByUsername` 메소드가 "testuser"를 인자로 받아 한 번 호출되었는지 검증
verify(userRepository, times(1)).findByUsername("testuser");

// `userRepository`의 `save` 메소드가 `user` 객체를 인자로 받아 한 번 호출되었는지 검증
verify(userRepository, times(1)).save(user);

 

왜 When을 써야 하는가?

 

when(userRepository.save(any(User.class))).thenReturn(user);

저장 후, 저장된 사용자 객체를 반환해야 하는데, 여기서 반환값을 user 객체로 설정하여 실제 데이터베이스에 접근하지 않고도 저장된 사용자 객체를 반환받는 상황을 시뮬레이션합니다. 여기서 when 구문이 사용되므로, eventRepository.save가 실행될 때 실제로 데이터베이스에 접근하지 않고, 미리 정의된 event 객체를 반환하도록 설정하는 것입니다.

 

즉 테스트 속도 향상, 실제 데이터베이스를 사용하지 않기 때문에 테스트 실행 속도가 빠릅니다.

또한 데이터베이스와 같은 외부 의존성에 영향을 받지 않고, 서비스 로직 자체를 독립적으로 테스트할 수 있습니다. 모킹(mocking)을 통해 외부 의존성을 제어하고 예측 가능한 동작을 설정함으로써, 테스트가 외부 환경에 좌우되지 않게 합니다.

 

물론 실제 데이터베이스와 연동 테스트를 해야하는 Repository 테스트 코드에는 when, verify를 쓰면 안된다.

 

 

doNothing() 메소드

service단 테스트 코드를 작성하는 도중 doNothing() 메소드라는 것에 대해서 배웠다.

무엇인가? 바로

doNothing().when(eventRepository).deleteById(eventId);

 

 eventRepository.deleteById(eventId)가 호출될 때 아무 작업도 하지 않도록 설정하는 것입니다. 이로 인해 deleteById 메소드가 호출되더라도 실제로 아무 일도 일어나지 않습니다.

  • 테스트의 의미: Repository 단에서 deleteById 메소드가 정상적으로 작동하는 것을 이미 테스트했다면, Service 단에서는 그 메소드가 호출되기만 하면 됩니다. 즉, Service 단에서는 해당 메소드가 호출되는지 여부만을 테스트하는 것입니다.

 코드 커버리지 분석  도구 JaCoCo

 코드 커버리지 : 소프트웨어의 테스트 케이스가 얼마나 충족되었는지를 나타내는 지표 중 하나

측정 기준은 크게 구문, 조건, 결정 3가지로 나뉜다. 가장 대표적으로 많이 사용되고 있는 측정 기준은 구문 입니다.

 

Jacoco는 자바 코드의 커버리지를 체크하는 라이브러리로,  테스트 코드가 현재 프로덕션코드의 얼마만큼 작성되었는지 퍼센테이지로 확인하도록 해주는 라이브러리 입니다. 만약 커버리지가 100퍼센트라면, 모든 프로덕션 코드에 대해서 테스트 코드가 작성되어 있는 상태라고 할 수 있을 것 입니다.

심지어 JaCoCo는 이렇게 커버리지 결과를 알려줄뿐만 아니라, 해당 커버리지가 사용자가 설정한 퍼센테이지에 미치지 못하면 build자체가 되지않게 설정하여, 테스트코드 작성을 강제합니다.

반응형

'Spring boot' 카테고리의 다른 글

CI/CD란 무엇인가  (0) 2024.07.25
RESTful API 란 무엇인가??  (0) 2024.07.25
Spring Boot 끄적끄적(4)  (0) 2024.07.18
Spring boot 끄적끄적(3)  (0) 2024.07.16
NoSQL vs SQL  (0) 2024.07.16