스프링 공부/게시판 프로젝트 만들기

[스프링] 32. MemberController.register 중복과 기타사유의 예외 테스트

장아장 2023. 2. 12. 17:50

이전에 null값으로 인한 예외가 발생되는 것을 컨트롤러 테스트를 만들어 검증해보았다. 

이번엔, 중복 발생시 / 비밀번호가 서로 다를 시 / 이메일이 형식에 맞지 않을 시 를 검증할 것이다. 

일단 중복이 발생하기 위해서는, 몇가지 선행되어야 할 내용이 있다. 

  • 매 순간 비교하기 위한 데이터 하나와, 기존의 데이터가 있어야 한다. 
  • 매 단위테스트마다 db를 초기화시켜 다른 테스트가 영향을 받으면 안된다. 

이런 점을 맞추기 위해, 

테스트를 실행하는 RegisterRequestDto를 반환하는 로직을 하나 만들었다. 

private static RegisterRequestDto makeTestRegister() {
    return RegisterRequestDto.builder()
            .username("test")
            .nickname("test")
            .email("test@test.com")
            .password("pass")
            .passwordCheck("pass")
            .build();
}

또한, 매 순간마다 똑같은 상황에서 테스트하기 위해 @BeforeEach로 db를 초기화시키는 기능을 추가했다. 

@BeforeEach
public void clear(){
    memberRepository.deleteAll();
}

마지막으로, Json타입으로 입력값을 만들어주기 위해 makeJson메서드도 만들었다. 

private String makeJson(Object object){
    try {
        return new ObjectMapper().writeValueAsString(object);
    } catch (JsonProcessingException e) {
        return "";
    }
}

 

이렇게, 필요한 기본 요소들을 만들어두고, 테스트를 만들었다. 

@Test
@DisplayName("아이디가 중복되었을 때 400에러를 반환하며 body 에서 중복됨을 알려준다.")
public void registerFail_DuplicatedUsername() throws Exception{
    //given
    memberService.registerNewMember(RegisterRequestDto.builder()
            .username("test")
            .nickname("aaa")
            .email("bbb@bbb.com")
            .password("ccc")
            .passwordCheck("ccc")
            .build());
    RegisterRequestDto registerRequestDto = makeTestRegister();
    //expected
    mvc.perform(MockMvcRequestBuilders.post("/join")
                    .contentType(MediaType.APPLICATION_JSON)
                    .content(makeJson(registerRequestDto)))
            .andExpect(MockMvcResultMatchers.status().isBadRequest())
            .andExpect(MockMvcResultMatchers.jsonPath("$.result.failMessage").value("이미 사용중인 아이디입니다."))
            .andDo(MockMvcResultHandlers.print());
}

기본적으로 비교하기 위한 대상 member를 만들어 서비스에서 생성시켜주었다. 

이후, Mockito로 로직을 수행시켰을 때 failMessage가 우리가 이전에, 

여기에 적어둔 message와 동일한지 체크하는 로직을 넣었다. ( => andExpect(MockMvcResultMatchers.jsonPath("$.result.failMessage").value("이미 사용중인 아이디입니다.") )

 

똑같은 방식으로 닉네임, 이메일도 만들어주었다. 

테스트 대상군인 given부분의 인스턴스값들만 조금씩 바꿔가며 테스트를 수행했다. 

전부 성공적으로 테스트가 이루어진다. 

 

이제, 이메일 형식이 올바르지 않은 경우, 비밀번호가 서로 일치하지 않은 경우를 테스트해보려고 한다. 

 

이번엔 비교할 데이터를 추가로 넣어야 할 필요가 없으므로, @BeforeEach로 리포지토리를 비워주던 로직은 제거했다. 

@SpringBootTest
@AutoConfigureMockMvc
public class MemberControllerTest_Register_ETC {

    @Autowired
    private MockMvc mvc;

    private String makeJson(Object object){
        try{
            return new ObjectMapper().writeValueAsString(object);
        }catch(JsonProcessingException e){
            return "";
        }
    }

    public RegisterRequestDto makeTest(){
        return RegisterRequestDto.builder()
                .username("test")
                .nickname("test")
                .email("test@test.com")
                .password("test")
                .passwordCheck("test")
                .build();
    }

이렇게 json을 만드는 로직, 테스트군을 만드는 로직만 두었다. 

 

이메일부터 테스트를 해보려고 하는데, 

위에 있는 test@test.com에서 예외가 나야하는 경우는, 

test

test@

test@test

test@test.

이렇게가 존재한다. 각 경우의 테스트코드를 모두 만들었다. 

또한,

@Test
@DisplayName("비밀번호가 서로 일치하지 않은 경우 400에러를 발생시키며 형식이상을 body 에 출력시킨다")
public void registerFail_PasswordMissMatch() throws Exception{
    //given
    RegisterRequestDto registerRequestDto = makeTest();
    registerRequestDto.setPassword("test1");
    //expected
    mvc.perform(MockMvcRequestBuilders.post("/join")
            .contentType(MediaType.APPLICATION_JSON)
            .content(makeJson(registerRequestDto)))
            .andExpect(MockMvcResultMatchers.status().isBadRequest())
            .andExpect(MockMvcResultMatchers.jsonPath("$.result.failMessage").value("비밀번호가 일치하지 않습니다."))
            .andDo(MockMvcResultHandlers.print());
}

password를 바꾸어, passwordCheck와 다른 값을 넣어주었다. 

이렇게 했을 때, 테스트를 실행시켜보았다. 

모든 경우에 대해서 테스트가 통과했다. 

여태까지 만들어진 로직중에, 추가해야 겠다 싶은 부분을 생각해보았다. 

MethodArgumentNotValidException이 발생했을 때, 발생한 이유가 많을 수 있다. 

ex) 아이디만 아니라, 닉네임, 비밀번호도 입력이 없을 수 있다. 

이런 경우에, 모든 경우를 예외문구로 body에 반환해주어야 하지 않을 까 생각이 든다. 

그런 점을 고려해서, 로직을 조금 더 다듬어보고, 다음 테스트로 넘어가야겠다.