에러 내용
Mockito를 이용하여 테스트를 하는 도중 Misplaced or misused argument matcher detected here:
에러가 발생했다.
에러 로그도 여기를 가리키고 있었다.
given(mapper.memberPatchToMember(Mockito.any(MemberDto.Patch.class)))
.willReturn(new Member());
given(memberService.updateMember(Mockito.any(Member.class)))
.willReturn(new Member());
해결 과정
크게 두 가지의 원인 로그가 있었는데,
This message may appear after an NullPointerException if the last matcher is returning an object like any() but the stubbed method signature expect a primitive argument, in this case, use primitive alternatives. when(mock.get(any())); // bad use, will raise NPE when(mock.get(anyInt())); // correct usage use
Also, this error might show up because you use argument matchers with methods that cannot be mocked. Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode(). Mocking methods declared on non-public parent classes is not supported.
첫 번째 로그를 보고 "Member.class
가 null을 반환할 수 있으니, any가 아닌 anyInt를 사용하라"라는 뜻으로 이해했다.
근데, Member는 클래슨데 Int로 어떻게 사용하라는거지? 라는 생각이 먼저 들었다.
그래서 다른 원인이 있을까 라는 생각으로 아래를 읽어보니, "Mock으로 사용할 수 없는 메서드를 인자 매처로 사용중일 수 있다." 라는 뜻으로 이해되는 로그가 있었다.
그렇게 코드를 살펴보다 도저히 모르겠어 any
사용시 NullPointerError
를 검색하기 시작했다. 찾다보니 테스트 객체에는 @InjectMocks
를 붙여줘야 한다는 것을 보게 되었고..
그럼 mapper나 service에 문제가 있나? 라는 생각으로 보게된 것이 바로 이것
@MockBean
private MemberService memberService;
@Autowired
private MemberMapper mapper;
mapper는 @Autowired
를 사용하여 빈을 주입받고 있었고, mapper @MockBean
으로 변경해봤더니 잘 동작하였다.
그래서 뭐가 문제였다는 거지?라는 생각으로 @Autowired
와 @MockBean
의 차이점을 찾아봤다.
필요한 의존 객체의 타입을 찾아 해당 빈을 주입
실제 구현된 내용을 사용한다.
결론
테스트를 하나 하나 하다보니 patch만 문제인줄 알고 있었지만 사실은 mapper의 빈 주입에 문제가 있어 전체적인 문제였다.
Autowired
로 실제 객체를 주입받아야 하는 이유로 mapper에서 가짜 객체를 받는 경우 Null을 가질 수 있음?을 컴파일러가 알려주는 과정에서 오류가 발생했다고 생각한다.