
Java 단위 테스트 작성에는 크게 2가지 라이브러리가 있는데
JUnit 5와 AssertJ 입니다
JUnit > 자바 단위 테스트를 위한 테스팅 프레임워크
AssertJ > 자바 테스트를 돕기 위한 문법 지원 라이브러리
assertEquals(a,b)와 assertThat(a).isEqualTo(b)라는 코드를 비교해보면
첫 번째는 a와 b가 동일한지 만 확인 가능하고
두 번째는 a가 실제 값, b가 예상 값이다 라는 것을 쉽게 확인 가능합니다.
따라서 저는 두 번째 문법을 더 선호합니다.(가 AssertJ 문법)
추가적으로 테스트 시에 실패 시 메세지를 통해서 예상값은 true 이지만 실제 값은 false 이다 뿐 아니라 어디에서 실패가 떳는지 추가적으로 원인이 무엇인지 도 상세하게 알려줍니다.
그러기에 혹시 JUnit을 사용하게 된다면 위와 같은 문법으로 사용하는 것을 적극 추천드립니다!
Test 코드 작성 시에는 given-when-then 패턴을 많이 사용합니다.
단위 테스트를 할 때 각 단계에 따라 나눠서 작성하게 되는데,
라는 것을 정확히 나타내는 것입니다.
그래서 저는 test에 대해 위의 템플릿을 미리 만들어서 사용하는 것을 추천드립니다.
@ExtendWith(MockitoExtension.class)
/*
개발자가 동작을 직접 제어할 수 있는 가짜 객체를 지원하는 테스트 프레임 워크
*/
public class AccountServiceTest extends DummyObject {
@InjectMocks
// @Mock 또는 @Spy 로 생성된 가짜 객체를 자동으로 주입시켜 주는 어노테이션
// 즉, 아래에서 가짜로 만든 repository를 service에 주입시키는 것
private AccountService accountService;
@Mock
// 가짜 객체를 만들어 반환해 주는 어노테이션
private UserRepository userRepository;
@Mock
private AccountRepository accountRepository;
@Spy
// Stub 하지 않은 메소드들을 원본 메소드 그대로 사용하는 어노테이션
// 참고로 ObjectMapper은 JSon 컨텐츠를 Java 객체로 deserialization or serialization
// 하는 jackson 라이브러리 클래스
// 참고로 OM은 생성 비용이 비싸서 bean 또는 static 으로 처리하는 것 이 좋습니다.
private ObjectMapper om;
@Test
public void 계좌등록_test() throws Exception {
// given
Long userId = 1L;
AccountReqDto.AccountSaveReqDto accountSaveReqDto = new AccountReqDto.AccountSaveReqDto();
accountSaveReqDto.setNumber(1111L);
accountSaveReqDto.setPassword(1234L);
// stub 1
// stub 는 의존성이 객체는 가짜 객체를 주입해 어떤 결과를 반환하라고 정해진 답변을
// 준비시켜야 합니다.
// Mockito에서는 doReturn : 가짜 객체가 특정한 값을 반환해양 하는 경우
// doNothing : 가짜 객체가 아무 것도 반환하지 않는 겨우
// doThrow : 가짜 객체가 예외를 발생시키는 경우
// 의 메소드를 제공합니다.
User ssar = newMockUser(userId, "ssar", "쌀");
when(userRepository.findById(any())).thenReturn(Optional.of(ssar));
// stub 2
when(accountRepository.findByNumber(any())).thenReturn(Optional.empty());
// stub 3
Account ssarAccount = newMockAccount(1L,1111L, 1000L, ssar);
when(accountRepository.save(any())).thenReturn(ssarAccount);
// when
AccountResDto.AccountSaveResDto accountSaveResDto = accountService.계좌등록(accountSaveReqDto, userId);
String responseBody = om.writeValueAsString(accountSaveResDto);
System.out.println("테스트: " + responseBody);
// then
assertThat(accountSaveResDto.getNumber()).isEqualTo(1111L);
}
}
여러 클래스, 여러 컴포넌트가 실제로 연결된 상태에서 테스트 한다가 다른 점
즉, 실제 환경과 유사하게 구성을 합니다.
단위 테스트에 비해서 속도가 느리고, 컨텍스트 로딩이나 I/O 등이 존재하기에 오버헤드가 존재합니다
// UserService와 UserRepository를 함께 테스트
@SpringBootTest
class UserIntegrationTest {
@Autowired
// 차이점
UserService userService;
@Test
void testUserRegistration() {
User user = new User("John");
userService.registerUser(user);
User result = userService.findUser("John");
assertNotNull(result);
assertEquals("John", result.getName());
}
}