JUnit Mock Object Equality
controller JUnit 테스트를 위해 service를 mocking 하여 테스트시 equals 관련 문제를 겪은 적이 있다. 우선 아래와 같은 코드가 있다고 할때,
설명)
이 controller의 service를 mocking 하여 Unit 테스트를 하려면 아래와 같이 될텐데,
이때 (2) 부분에서 equals 비교가 일어 나는듯. controller가 request 받았을때 만든 command 객체는 mock에 넣어준 request command 객체와 다르기(referenece 비교) 때문에 테스트가 실패한다.
간단하게는 RequestCommand에 equals/hashCode를 override 하는 것이지만, reference 비교가 유효한 곳에는 그렇게 할 수 없다. 이 때는 아래처럼 mokito의 argThat()을 사용해 보자.
위 처럼 ArgumentMatcher를 구현해주면 argThat()에서 이를 이용해 매칭을 하니 equals/hashCode를 override 하지 않아도 된다.
update) argThat()을 사용하면 Matcher를 사용하지 않아도 될듯~
참고: https://automationrhapsody.com/assert-mockito-mock-method-arguments-no-equals-method-implemented/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | // RestController @GetMapping(value = "/test/{id}/info") public TestInfo getTestInfo(@Valid RequestCommand command) { return TestInfoService.getTestInfo(command); } // Service public TestInfo getTestInfo(RequestCommand command) { // ... command에 따른 로직 return new TestInfo("test"); } // Command class public class RequestCommand { private String id; // getters & setters } // Domain class public class TestInfo { private String str; public TestInfo(String str) { this.str = str; } // getters & setters } |
- controller는 path variable로 id를 RequestCommand 객체로 받는다.
- 이 command를 DTO로 service로 넘겨 연산을 하고 entity를 받는다.
- 받은 entity를 json으로 응답한다.
이 controller의 service를 mocking 하여 Unit 테스트를 하려면 아래와 같이 될텐데,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | @Test public void getTestInfo_200() throws Exception { RequestCommand request = new RequestCommand(); request.setId("1"); TestInfo info = new TestInfo("test~"); doReturn(info) .when(TestInfoService) // (1) service mock .getTestInfo(request)); // (2) 문제 부분 // then mvc.perform(get("/test/{id}/info", "1") .contentType(APPLICATION_JSON)) .andDo(print()) .andExpect(jsonPath("$.str").value("test~")); } |
이때 (2) 부분에서 equals 비교가 일어 나는듯. controller가 request 받았을때 만든 command 객체는 mock에 넣어준 request command 객체와 다르기(referenece 비교) 때문에 테스트가 실패한다.
간단하게는 RequestCommand에 equals/hashCode를 override 하는 것이지만, reference 비교가 유효한 곳에는 그렇게 할 수 없다. 이 때는 아래처럼 mokito의 argThat()을 사용해 보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | @Test public void getTestInfo_200() throws Exception { RequestCommand request = new RequestCommand(); request.setId("1"); TestInfo info = new TestInfo("test~"); doReturn(info) .when(TestInfoService) // mocking된 서비스 .getTestInfo(argThat(new ArgumentEqualityMatcher(request))); // object equals가 필요한 부분 // then mvc.perform(get("/test/{id}/info", "1") .contentType(APPLICATION_JSON)) .andDo(print()) .andExpect(jsonPath("$.str").value("test~")); } // "equals" for mock arguments. private class ArgumentEqualityMatcher implements ArgumentMatcher<RequestCommand> { private final FlagshipStoreCommand expected; ArgumentEqualityMatcher(FlagshipStoreCommand expected) { this.expected = expected; } @Override public boolean matches(FlagshipStoreCommand command) { return expected.getId() == command.getId() } } |
위 처럼 ArgumentMatcher를 구현해주면 argThat()에서 이를 이용해 매칭을 하니 equals/hashCode를 override 하지 않아도 된다.
update) argThat()을 사용하면 Matcher를 사용하지 않아도 될듯~
참고: https://automationrhapsody.com/assert-mockito-mock-method-arguments-no-equals-method-implemented/
댓글
댓글 쓰기