Closed 2jigoo closed 1 year ago
@Test
void dateFormat() {
LocalDate date = LocalDate.of(1945, 8, 15);
String dateText = formatDate(date);
// X
// - 문자열 연결이 있어 복잡
// - date.getMonth()로 잘못 사용하면?
assertEquals(date.getYear() + "년 " +
date.getMonthValue() + "월 " +
date.getDayOfMonth() + "일", dateText);
// O
// 해당 테스트가 실패하면, formatDate 메서드만 확인하면 된다.
assertEquals("1945년 8월 15일", dateText);
}
// 필드 또는 변수 사용 X
// 테스트가 실패했을 때, 사용했던 필드나 변수가 무엇인지 확인해야하는 번거로움
// 값을 바로 사용하면 직관적으로 확인할 수 있음
// private List<Integer> answers = Arrays.asList(1, 2, 3, 4);
// private Long respondentId = 100L;
@Test
public void saveAnswerSuccessfully() {
// 답변할 설문이 존재
Survey survey = SurveyFactory.createApporvedSurvely(1L);
surveyRepository.save(survey);
SurveyAnswerRequest surveyAnswer = SurveyAnswerRequest.builder()
.surveyId(1L)
.respondentI2(100L)
.answers(Arrays.asList(1, 2, 3, 4))
.build();
svc.answerSurvey(surveyAnswer);
// 저장 결과 확인
SurveyAnswer savedAnswer = memoryRepository.findBySurveyAndRespondent(1L, 100L);
assertAll(
() -> assertEquals(100L, savedAnswer.getRespondentId),
() -> assertEquals(4, savedAnswer.getAnswers().size()),
() -> assertEquals(1, savedAnswer.getAnswers().get(0)),
() -> assertEquals(2, savedAnswer.getAnswers().get(1)),
() -> assertEquals(3, savedAnswer.getAnswers().get(2)),
() -> assertEquals(4, savedAnswer.getAnswers().get(3))
)
}
@Test
void weakPassword() {
// 약한 암호인 경우, UserRegister가 의도한 대로 동작하는지를 확인하는 테스트
// - "pw"를 넘겼을 때, 약한 암호인지 확인하는 코드가 아님
// - 임의의 문자열에 대해 true를 리턴해도 이 테스트 의도에 전혀 문제되지 않음!
// X
// BDDMockito.given(mockPasswordChecker.checkPasswordWeak("pw"))
BDDMockito.given(mockPasswordChecker.checkPasswordWeak(Mockito.anyString()))
.willReturn(true);
assertThrows(WeakPasswordException.class, () -> {
userRegister.register("id", "pw", "email");
});
}
@Test
void checkPassword() {
userRegister.register("id", "pw", "email");
BDDMockito.then(mockPasswordChecker)
.should()
// .checkPasswordWeak("pw");
.checkPasswordWeak(Mockito.anyString());
}
@Test
void checkPassword() {
userRegister.register("id", "pw", "email");
// PasswordChecker#checkPasswordWeak() 메서드 호출 여부 검사
BDDMockito.then(mockPasswordChecker)
.should()
.checkPasswordWeak(Mockito.anyString());
// UserRepository#findById() 메서드를 호출하지 않는 것을 검사
BDDMockito.then(mockRepository)
.should(Mockito.never())
.findById(Mockito.anyString());
}
// 가짜 구현으로 대체 하기 어려운 레거시 코드
public void changeEmail(String id, String email) {
int cnt = userDao.countById(id);
if (cnt == 0) {
throw new NoUserException();
}
userDao.updateEmail(id, email);
}
@Test
void changeEmailSuccessfully() {
given(mockDao.countById(Mockito.anyString())).willReturn(1);
// 이메일 수정 시
emailService.changeEmail("id", "new@somehost.com");
// updateEmail 메서도 호출 검증
then(mockDao)
.should()
.updateEmail(Mockito.anyString(), Mockito.matches("new@somehost.com"));
}
기능을 검증할 수단이 구현 검증뿐이라면 모의 객체를 사용해서 테스트 코드 작성. 테스트 코드 작성 후엔 점진적으로 코드를 리팩토링하여 구현이 아닌 결과를 검증할 수 있도록 해야한다.
@BeforeEach
와 같은 셋업 메서드를 이용해 테스트 메서드의 상황 설정을 지양한다.
테스트 메서드는 검증을 목표로 하는 하나의 완전한 프로그램이어야 한다. 각 테스트 메서드는 검증 내용을 스스로 잘 설명할 수 있어야 한다.
변경 전
@BeforeEach
void setUp() {
changeService = new ChangeUserService(memeoryRepository);
memoryRepository.save(
new User("id", "name" "pw", new Address("서울", "북부")
);
}
@Test
void changeAddress() {
changeService.changeAddress("id", new Address("서울", "남부"));
User user = memoryRepository.findById("id");
assertEquals("서울", user.getAddress().getCity());
}
변경 후
@BeforeEach
void setUp() {
changeService = new ChangeUserService(memeoryRepository);
}
@Test
void changeAddress() {
memoryRepository.save(
new User("id", "name", "pw", new Address("경기", "남부")
);
changeService.changeAddress("id", new Address("서울", "남부"));
User user = memoryRepository.findById("id");
assertEquals("서울", user.getAddress().getCity());
}
Chapter 10. 테스트 코드와 유지보수 (1/2)
목표