테스트 케이스를 만들다가 멘탈이 나가버릴것만 같다. 멘토님께서 트러블 슈팅을 해보라 하셔서 바로 해본다.
@PreAuthorize("isAuthenticated()")
@PostMapping("/{user-id}")
public ResponseEntity<?> postResult(@AuthenticationPrincipal UserPrincipal userPrincipal,
@RequestBody CalculatorDto.Post requestBody) {
User user = userPrincipal.getUser();
Calculator calculator = calculatorService.createResult(
calculatorMapper.calculatorPostToCalculator(requestBody),
user,
physicalService.findPhysicalByUserId(user.getUserId())
);
URI uri = UriUtil.createUri(DEFAULT_URL, calculator.getCalculatorId());
CalculatorDto.Response response = calculatorMapper.calculatorToResponse(calculator);
//response.setUserId(userPrincipal.getUser().getUserId());
response.setCalculatorId(calculator.getCalculatorId());
return ResponseEntity.created(uri).body(ApiResponse.ok("data", response));
}
1) postResult()
먼저, 내가 만든 postmapping method인 postResult()
@Service
@RequiredArgsConstructor
public class CalculatorService {
private final CalculatorRepository calculatorRepository;
private final CustomBeanUtil<Calculator> customBeanUtil;
public Calculator createResult(Calculator calculator, User user, Physical physical) {
if (physical.getWeight() == null || physical.getHeight() == null || physical.getGender() == null) {
throw new BusinessLogicException(ExceptionCode.CALCULATOR_NO_USER_INFO);
}
calculator.setResult(CalculatorHelper.calculateResultWithGender(calculator.getActivityLevel(),calculator.getGoal(), physical));
calculator.setUser(user);
calculator.setPhysical(physical);
calculator.setCalculatorId(calculator.getCalculatorId());
calculator.setGoal(calculator.getGoal());
calculator.setActivityLevel(calculator.getActivityLevel());
calculator.setCreatedAt(calculator.getCreatedAt());
calculator.setModifiedAt(calculator.getCreatedAt());
return calculatorRepository.save(calculator);
}
2) createResult()
^postResult 에서 사용한 createResult()
@WithMockUserCustom
@Test
@DisplayName("[테스트] 계산기 결과 등록")
void postResultTest() throws Exception {
//given
CalculatorDto.Post requestBody = new CalculatorDto.Post(Goal.DIET,ActivityLevel.EXTRA_ACTIVE);
requestBody.setGoal(Goal.DIET);
requestBody.setActivityLevel(ActivityLevel.EXTRA_ACTIVE);
Physical physical = new Physical();
physical.setPhysicalId(1L);
physical.setWeight(78);
physical.setHeight(173);
physical.setBirth(19961213);
physical.setGender(Physical.Gender.MALE);
physical.setUser(user);
physical.setCreatedAt(LocalDateTime.now());
physical.setModifiedAt(LocalDateTime.now());
Calculator calculator = new Calculator();
calculator.setCalculatorId(1L);
calculator.setGoal(Goal.DIET);
calculator.setActivityLevel(ActivityLevel.EXTRA_ACTIVE);
calculator.setResult(3011.0);
calculator.setUser(user);
calculator.setPhysical(physical);
calculator.setCreatedAt(LocalDateTime.now());
calculator.setModifiedAt(LocalDateTime.now());
given(calculatorService.createResult(calculator, user, physical))
.willReturn(calculator);
given(physicalService.findPhysicalByUserId(anyLong())).willReturn(physical);
postResource(DEFAULT_URL + "/{user-id}", requestBody, user.getUserId())
.andExpect(status().isOk())
.andExpect(jsonPath("$.body.data").isNotEmpty());
//.andExpect(jsonPath("$.data.result").value(calculator.getResult()));
}
3) postResultTest()
^테스트코드인 postResultTest
하..자꾸 createResult에서 문제가 발생한다. 포스트맨에서는 잘만되는데, 왜 테스트하면 null값을 반환하지? 내가 설정하지않은게 있나?
디버깅 결과 calculator가 자꾸 null이 나온다!
set 할 수 있는건 전부다 set해줬는데도, null을 반환한다. 으아아!!!
하지만.
테스트케이스 작성에 있어 근본부터 모르고 도전했던것이 문제였다.
기본적으로 내가 controller에서 사용한 service의 메서드, mapper의 메서드를 given으로 주지 않았다.
그래서 수정한 코드는 이렇다.
@WithMockUserCustom
@Test
@DisplayName("[테스트] 계산기 결과 생성")
void postResultTest() throws Exception {
CalculatorDto.Post requestBody = new CalculatorDto.Post(Goal.DIET, ActivityLevel.EXTRA_ACTIVE);
given(calculatorService.createResult(Mockito.any(Calculator.class), Mockito.any(User.class), Mockito.any(Physical.class)))
.willReturn(calculator);
given(calculatorMapper.calculatorPostToCalculator(Mockito.any(CalculatorDto.Post.class)))
.willReturn(calculator);
given(physicalService.findPhysicalByUserId(anyLong()))
.willReturn(physical);
given(calculatorMapper.calculatorToResponse(Mockito.any(Calculator.class)))
.willReturn(calculatorDtoResponse);
postResource(DEFAULT_URL + "/{user-id}", requestBody, user.getUserId())
.apply(true)
.andExpect(status().isCreated())
.andExpect(jsonPath("$.body.data").isNotEmpty())
.andDo(restDocs.document(
customRequestFields(CalculatorDto.Post.class, new LinkedHashMap<>() {{
put("goal", "운동 목표, String");
put("activityLevel", "활동 정도, String");
}}
)
));
}
4) 완성한 postResultTest()
3) 코드에서는 기본적으로 given으로 createResult와 findPhysicalByUserId 만을 테스트했고, 4)에서 수정한것은 calculatorPostToCalculator과 calculatorToResponse를 given으로 테스트 했다. 그리고 또 자랑할만한 것은 3)에서 physical과 calculator를 일일이 setup 해주었지만, 저 객체들은 postResult에서만 사용되는 객체가 아니기 때문에 따로 setup으로 빼줬다.
@BeforeEach
void setup() throws Exception {
Map<String, Object> userResource = userResource();
user = (User) userResource.get("user");
physical = new Physical(1L, 19961213, 173, 78, Physical.Gender.MALE, user);
calculator = new Calculator(1L, Goal.DIET, ActivityLevel.VERY_ACTIVE, 3011.0, user, physical);
calculatorDtoResponse = new CalculatorDto.Response(3011.0, 1L, ActivityLevel.VERY_ACTIVE,
Goal.DIET, LocalDateTime.now(), LocalDateTime.now());
}
5) setup()
이렇게 setup으로 미리 객체들을 세팅해주고 이 객체들을 이용해 테스트케이스를 작성해나갔다.
그렇게 해서 나머지 CRUD 메서드들도 가뿐하게 테스트케이스작성을 마칠 수 있었다.
/** 이후에 멘토링을 통해 setter를 쓰는건 현업에서 거의 없다고 한다는 걸 들었다. setter에 절여진 내 뇌를 바꿔야 겠다는 생각을 했다.
setter대신 builder를 쓴다고 하는데 안써봐서 어떻게 써야할지 알아보고 또 블로깅으로 남겨야 겠다. **/
'부트캠프 > 백' 카테고리의 다른 글
클라우드 운영전략 (0) | 2023.02.07 |
---|---|
Github Actions (0) | 2023.02.06 |
Section3-3 (0) | 2023.02.04 |
자동배포방식 - Pipeline (0) | 2023.02.04 |
Docker - container (0) | 2023.02.03 |