본문 바로가기
부트캠프/백

트러블 슈팅 - 테스트케이스(해결완료)

by 티코딩 2023. 3. 23.

테스트 케이스를 만들다가 멘탈이 나가버릴것만 같다. 멘토님께서 트러블 슈팅을 해보라 하셔서 바로 해본다.

@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