[에러노트 ] mockito를 이용한 테스트 중 에러 들

hyewon jeong·2023년 1월 30일
0

에러노트

목록 보기
17/40

💡 에러 1 Cannot invoke "~" because "this.jwtUtil" is null

1 발생

userService test 중 회원가입은 잘되었으나 로그인때 에러발생함


2 코드

Cannot invoke "com.example.myblog1.common.jwt.JwtUtil.createToken(java.lang.String, com.example.myblog1.user.entity.UserRoleEnum)" because "this.jwtUtil" is null
java.lang.NullPointerException: Cannot invoke "com.example.myblog1.common.jwt.JwtUtil.createToken(java.lang.String, com.example.myblog1.user.entity.UserRoleEnum)" because "this.jwtUtil" is null


3 원인

@Slf4j
@Component
@NoArgsConstructor(force = true,access = AccessLevel.PROTECTED)
@RequiredArgsConstructor
public class JwtUtil {

   ......

    @Value("${jwt.secret.key}")
    private String secretKey;
    .....

    @PostConstruct
    public void init() {
        byte[] bytes = Base64.getDecoder().decode(secretKey);
        key = Keys.hmacShaKeyFor(bytes);
    }

@PostConstructor가 동작하지 않기 때문이다.


4 해결

@PostConstructor가 동작하지 않기 때문에, 임의로 실행시켜야 함
@mock 객체들 선언이 끝난 쪽에 아래코드를 넣어주면 해결 됨

    @BeforeEach
    void prepare() {
        ReflectionTestUtils.setField(jwtUtil, 
                                 "secretKey", // jwtUtil의 secretKey값이 저장될 변수
                                "7ZWt7ZW0OTntmZTsnbTtjIXtlZzqta3snYTrhIjrqLjshLjqs4TroZzrgpjslYTqsIDsnpDtm4zrpa3tlZzqsJzrsJzsnpDrpbzrp4zrk6TslrTqsIDsnpA="); // secretKey의 값
        jwtUtil.init(); // jwtUtil에서 @PostConstructor가 동작하지 않기 때문에, 임의로 실행시켜야 함
    }

💡 에러 2 Strict stubbing argument mismatch. Please check:

1 발생

userController Test 중 생긴 에러


2 코드

Request processing failed; nested exception is org.mockito.exceptions.misusing.PotentialStubbingProblem:
Strict stubbing argument mismatch. Please check:

  • this invocation of 'signup' method:
    userService.signup(
    xcom.example.myblog1.user.dto.📌SignupRequest@e415a66
    );
    -> at com.example.myblog1.user.controller.UserController.signup(UserController.java:32)
  • has following stubbing(s) with different arguments:
    1. userService.signup(
    com.example.myblog1.user.dto.📌SignupRequest@cd2df889
    );
    -> at com.example.myblog1.user.controller.UserControllerTest.signup1(UserControllerTest.java:61)
    Typically, stubbing argument mismatch indicates user mistake when writing tests.
    Mockito fails early so that you can debug potential problem easily.

3 원인

이 목객체로 생성한 리퀘스트와

content(new Gson().toJson(request))); 

이 리퀘스트가 일치 하지 않는다는 말이다.

위의 📌 이 부분을 봐도 객체의주소값이 다르다고 말해주고 있다.
왜 객체의 주소값이 달려졌을까?

  ResultActions resultActions = mockMvc.perform(
                MockMvcRequestBuilders.post("/api/users/signup")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(new Gson().toJson(request))); 

content(new Gson().toJson(request)));

이 소스 코드에서 new를 사용해서 새로운 인스턴스를 만들었기 때문에, 목킹할 때 사용한 아규먼트와 일치하지 않아서 발생할 에러이다.


4 해결

어떤 타입의 postRequest 인스턴스를 받는지 상관없이 내가 미리 만들어둔 postRequest을 리턴하게 목킹하고 싶다면 any()를 사용하면 해결 됨

when(userService.signup(any(SignupRequest.class)))
                .thenReturn(response);

완성코드

@ExtendWith(MockitoExtension.class)
class UserServiceTest {

    @Mock
    private UserRepository userRepository;
    @InjectMocks
    private UserService userService;

    @Spy
    private JwtUtil jwtUtil;

    @BeforeEach
    void prepare() {
        ReflectionTestUtils.setField(jwtUtil,
                "secretKey", // jwtUtil의 secretKey값이 저장될 변수
                "7ZWt7ZW0OTntmZTsnbTtjIXtlZzqta3snYTrhIjrqLjshLjqs4TroZzrgpjslYTqsIDsnpDtm4zrpa3tlZzqsJzrsJzsnpDrpbzrp4zrk6TslrTqsIDsnpA="); // secretKey의 값
        jwtUtil.init(); // jwtUtil에서 @PostConstructor가 동작하지 않기 때문에, 임의로 실행시켜야 함
    }

    @Spy
    private BCryptPasswordEncoder passwordEncoder;


   
    @Test
    @DisplayName("로그인")
    void login() {   // 에러 왜 발생하는지 체크하기 -> 이유 : jwtUtil에서 @PostConstructor가 동작하지 않기 때문에, 임의로 실행시켜주니까 에러해결됨
        //given
        LoginRequest request = LoginRequest.builder()
                .username("pororo")
                .password("12341234")
                .build();
        MockHttpServletResponse servletResponse = new MockHttpServletResponse();//웹서버가 관장하는 값을 넣어줌

        //목객체의 리턴값
        User user = new User("pororo", passwordEncoder.encode("12341234"), "pororo@naver.com", UserRoleEnum.USER);
        when(userRepository.findByUsername(any(String.class)))
                .thenReturn(Optional.of(user));


        //when
        ResponseStatusDto response = userService.login(request, servletResponse);
        //then
        assertThat(response.getStatusCode()).isEqualTo(StatusEnum.LOGIN_SUCCESS.getStatusCode());
        assertThat(response.getMsg()).isEqualTo(StatusEnum.LOGIN_SUCCESS.getMsg());
        assertThat(servletResponse.getHeaderValue("Authorization").toString()).isNotEmpty();

        verify(userRepository,times(1)).findByUsername(any(String.class));

    }
}

💡 에러3 . Please remove unnecessary stubbings or use 'lenient' strictness

1 발생

mockMvc를 이용한 userController 단 테스트 코드 작성 후 런 하였더니 생긴 에러


2 코드

Unnecessary stubbings detected.
Clean & maintainable test code requires zero unnecessary code.
Following stubbings are unnecessary (click to navigate to relevant line of code):
  1. -> at com.example.myblog1.user.controller.UserControllerTest.signup_failed_pw(UserControllerTest.java:105)
Please remove unnecessary stubbings or use 'lenient' strictness. More info: javadoc for UnnecessaryStubbingException class.
org.mockito.exceptions.misusing.UnnecessaryStubbingException: 
Unnecessary stubbings detected.
Clean & maintainable test code requires zero unnecessary code.

3 원인

  1. -> at com.example.myblog1.user.controller.UserControllerTest.signup_failed_pw(UserControllerTest.java:105)
Please remove unnecessary stubbings or use 'lenient' strictness.

불필요한 스터빙을 하지 않도록 되어있는데, 현재 코드 105줄에 쓰이지 않는 스터빙을 해놨기 때문에 저런 메시지가 보이는 것이고, lenient는 그런 제약을 느슨하게 허용하게 해줍니다.


4 해결

 lenient().when(userService.signup(request))
                .thenReturn(response);

lenient는 그런 제약을 느슨하게 허용하게 함으로 에러 해결함

💡 에러4

1 발생


2 코드

3 원인


4 해결

profile
개발자꿈나무

0개의 댓글