병갈이 블록

[우아한 테크캠프 Pro 2기] JPA 미션 - Mockito 오류 관련 정리. 본문

개발공부 이야기(New)/우테캠Pro2기

[우아한 테크캠프 Pro 2기] JPA 미션 - Mockito 오류 관련 정리.

woojang 2021. 6. 1. 00:42

연관관계 설정 뒤 Repository까지 수정을 마치고 ServiceTest 클래스의 테스트 코드를 검증 하는 도중 만난 오류이다.

우선 오류 내용은 아래와 같다.

Argument(s) are different! Wanted:
deleteHistoryService.saveAll(
    java.util.Arrays$ArrayList@d3c52ba7
);
-> at qna.service.QnaServiceTest.verifyDeleteHistories(QnaServiceTest.java:95)
Actual invocations have different arguments:
deleteHistoryService.saveAll(
    [DeleteHistory{id=null, contentType=QUESTION, contentId=1, deletedById=1, createDate=2021-06-01T00:21:25.194201}, DeleteHistory{id=null, contentType=ANSWER, contentId=1, deletedById=1, createDate=2021-06-01T00:21:25.194427}]
);
-> at qna.service.QnaService.deleteQuestion(QnaService.java:56)

Comparison Failure: 
<Click to see difference>

Argument(s) are different! Wanted:
deleteHistoryService.saveAll(
    java.util.Arrays$ArrayList@d3c52ba7
);
-> at qna.service.QnaServiceTest.verifyDeleteHistories(QnaServiceTest.java:95)
Actual invocations have different arguments:
deleteHistoryService.saveAll(
    [DeleteHistory{id=null, contentType=QUESTION, contentId=1, deletedById=1, createDate=2021-06-01T00:21:25.194201}, DeleteHistory{id=null, contentType=ANSWER, contentId=1, deletedById=1, createDate=2021-06-01T00:21:25.194427}]
);
-> at qna.service.QnaService.deleteQuestion(QnaService.java:56)

	at qna.service.QnaServiceTest.verifyDeleteHistories(QnaServiceTest.java:95)
	at qna.service.QnaServiceTest.delete_성공(QnaServiceTest.java:55)
	... 이하 생략

 

오류를 해결한 방법은 예외 발생 지점부터 역으로 찾아가는거였다.

오류 발생 코드 위치는 아래와 같다.

List<DeleteHistory> deleteHistories = Arrays.asList(
    new DeleteHistory(ContentType.QUESTION, question.getId(), question.getWriterId(), LocalDateTime.now()),
    new DeleteHistory(ContentType.ANSWER, answer.getId(), answer.getWriterId(), LocalDateTime.now())
);
verify(deleteHistoryService).saveAll(deleteHistories);	// <-- 이 라인

처음보는 내용이라 검색을 해보았다. 그리고 아래와 같은 내용을 확인했다.

- verify(mock).method(param);
    = 해당 Mock Object 의 메소드를 호출했는지 검증

 

실제 코드로 이야기를 해보면 deleteHistoryService에 있는 saveAll 메서드가 호출되었는지 검증하는 코드이다.

하지만 저 코드라인에 도착하기 전에 해당 메서드가 분명히 호출이 되었다. 그래서 다시 한번 에러 내용을 유심히 보았다. 그리고 자꾸 눈에 들어오는 단어.

Argument(s) are different!

 

그래서 다시한번 param으로 넘어가는 값을 세팅하는 부분을 유심히 보았다. 그랬더니....

for (Answer answer : answers) {
    answer.setDeleted(true);
    deleteHistories.add(new DeleteHistory(ContentType.ANSWER, answer.getId(), answer.getWriter(), LocalDateTime.now()));
}
deleteHistoryService.saveAll(deleteHistories);

=========================================================================================================

List<DeleteHistory> deleteHistories = Arrays.asList(
    new DeleteHistory(ContentType.QUESTION, question.getId(), question.getWriterId(), LocalDateTime.now()),
    new DeleteHistory(ContentType.ANSWER, answer.getId(), answer.getWriterId(), LocalDateTime.now())
);
verify(deleteHistoryService).saveAll(deleteHistories);

값을 세팅하는 구조는 틀리지만 그건 중요한게 아니고, 셋팅되고 있는 파라미터를 봐야한다.

 

결론부터 이야기 하자면, DeleteHistory의 생성자가 2개 존재하고 위와 아래가 각기 다른 생성자를 호출하고 있다.

3번째 파라미터의 getter를 보면 위는 Writer를 가져오고 아래는 WriterId를 가져오고 있다.

getWriter는 User객체를, getWriterId는 Long을 반환하여 실제 로직상 생성된 DeleteHistory 객체는 User 객체를 주입받아 not null상태이고, 검증용으로 생성된 객체는 User객체가 null인 상태이다. 실제로 입력된 값과 검증용 값이 달랐던 것이다.

 

문제의 발단은, 연관관계를 설정하면서 기존에 id값을 받던 부분을 객체로 받도록 수정하는 과정에서 과도기적으로 남아있었던 생성자가 존재하면서 생신 문제였다. 미리 생성자를 제거했다면 검증부분에 컴파일 에러가 발생해서 사전에 문제를 인지 할 수 있었을 것이다.

 

오늘의 교훈! 오류 메시지를 잘 보자! 잘 보면 답이 보인다! 그리고 삭제할 코드는 미리미리...ㅎㅎㅎㅎ

 

배운것 하나 - verify(mock).method(param)은 메소드 호출 여부 및 파라미터 일치여부까지 확인을 한다는것!

** 파라미터 내용까지는 검색이 잘 안되는데...별도의 설정 없이도 파라미터 값이 검증되는 걸로 봐서는 기본으로 제공하는 기능이 아닌가 싶다. 하지만 생각해 봐야 할 건 값 자체의 일치여부는 아닌 듯 하다.(검증용 코드에 날짜값을 완전 다른 값으로 세팅해도 성공으로 넘어간다.) 상태에 대한 비교인건가....이거는 좀 확인 해 봐야할 것 같다.

Comments