전체 코드는 여기에서 볼 수 있습니다.

 

1. 유저 생성 API - Controller, Service, Repository, Entitiy, UserDTO

- controller

@RestController
@RequiredArgsConstructor
public class UserController {
    private final UserService userService;

    @PostMapping("/user")
    @ResponseStatus(value = HttpStatus.CREATED)
    public SuccessResponse<UserDTO> createUser(@RequestBody @Valid UserDTO userDTO) {
        User user = userService.createUser(userDTO);

        return SuccessResponse.success(UserDTO.builder()
                .id(user.getId())
                .build());
    }
}

 

- service

@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository;

    public User createUser(UserDTO userDTO) {
        User user = User.builder()
                .email(userDTO.getEmail())
                .password(userDTO.getPassword())
                .nickname(userDTO.getNickname())
                .createdBy(LocalDateTime.now())
                .build();

        return userRepository.save(user);
    }
}

 

- repository

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}

 

- entity

@Entity
@Builder
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String email;

    private String password;

    private String nickname;

    private LocalDateTime createdBy;
}

 

- userDTO

@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class UserDTO {
    private Long id;

    @Email(message = "이메일 양식이 아닙니다.")
    @NotBlank(message = "이메일은 필수값 입니다.")
    private String email;

    @NotBlank(message = "비밀번호는 필수값 입니다.")
    private String password;

    @NotBlank(message = "닉네임은 필수값 입니다.")
    private String nickname;

    private LocalDateTime createdBy;
}

 

2. 유저 생성 테스트코드 작성 - ControllerTest, ServiceTest

- controllerTest

@ExtendWith(SpringExtension.class)
@SpringBootTest
@AutoConfigureMockMvc
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class UserControllerTest {
    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private UserService userService;

    public UserDTO initUserDTO() {
        return UserDTO.builder()
                .email("email@email.com")
                .password("password")
                .nickname("nickname")
                .build();
    }

    @Test
    public void 유저_생성() throws Exception {
        // given
        UserDTO userDTO = initUserDTO();

        // when
        ResultActions perform = mockMvc.perform(post("/user")
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(userDTO)));

        // then
        perform
                .andExpect(status().isCreated())
                .andExpect(jsonPath("message").exists())
                .andExpect(jsonPath("message").value("success"))
                .andExpect(jsonPath("data").hasJsonPath())
                .andExpect(jsonPath("data.id").exists())
                .andExpect(jsonPath("data.id").value(1L))
                .andDo(print());
    }

    @Test
    public void 유저_생성_이메일_양식아님() throws Exception {
        // given
        UserDTO userDTO = initUserDTO();
        userDTO.setEmail("email");

        // when
        ResultActions perform = mockMvc.perform(post("/user")
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(userDTO)));

        // then
        perform
                .andExpect(jsonPath("message").exists())
                .andExpect(jsonPath("message").value("bad_request"))
                .andExpect(jsonPath("errors").hasJsonPath())
                .andExpect(jsonPath("errors", hasSize(1)))
                .andExpect(jsonPath("errors[*].field", containsInAnyOrder("email")))
                .andExpect(jsonPath("errors[*].message", containsInAnyOrder("이메일 양식이 아닙니다.")))
                .andExpect(status().isBadRequest())
                .andDo(print());
    }

    @Test
    public void 유저_생성_이메일_없음() throws Exception {
        // given
        UserDTO userDTO = initUserDTO();
        userDTO.setEmail("");

        // when
        ResultActions perform = mockMvc.perform(post("/user")
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(userDTO)));

        // then
        perform
                .andExpect(jsonPath("message").exists())
                .andExpect(jsonPath("message").value("bad_request"))
                .andExpect(jsonPath("errors").hasJsonPath())
                .andExpect(jsonPath("errors", hasSize(1)))
                .andExpect(jsonPath("errors[*].field", containsInAnyOrder("email")))
                .andExpect(jsonPath("errors[*].message", containsInAnyOrder("이메일은 필수값 입니다.")))
                .andExpect(status().isBadRequest())
                .andDo(print());
    }

    @Test
    public void 유저_생성_패스워드_없음() throws Exception {
        // given
        UserDTO userDTO = initUserDTO();
        userDTO.setPassword("");

        // when
        ResultActions perform = mockMvc.perform(post("/user")
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(userDTO)));

        // then
        perform
                .andExpect(jsonPath("message").exists())
                .andExpect(jsonPath("message").value("bad_request"))
                .andExpect(jsonPath("errors").hasJsonPath())
                .andExpect(jsonPath("errors", hasSize(1)))
                .andExpect(jsonPath("errors[*].field", containsInAnyOrder("password")))
                .andExpect(jsonPath("errors[*].message", containsInAnyOrder("비밀번호는 필수값 입니다.")))
                .andExpect(status().isBadRequest())
                .andDo(print());
    }

    @Test
    public void 유저_생성_닉네임_없음() throws Exception {
        // given
        UserDTO userDTO = initUserDTO();
        userDTO.setNickname("");

        // when
        ResultActions perform = mockMvc.perform(post("/user")
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(userDTO)));

        // then
        perform
                .andExpect(jsonPath("message").exists())
                .andExpect(jsonPath("message").value("bad_request"))
                .andExpect(jsonPath("errors").hasJsonPath())
                .andExpect(jsonPath("errors", hasSize(1)))
                .andExpect(jsonPath("errors[*].field", containsInAnyOrder("nickname")))
                .andExpect(jsonPath("errors[*].message", containsInAnyOrder("닉네임은 필수값 입니다.")))
                .andExpect(status().isBadRequest())
                .andDo(print());
    }
}

 

- serviceTest

기존에는 Mock을 활용하여 유닛테스트를 하였으나 과연 실제 상황에서 잘 작동하는가에 대해 의문이 들어 통합테스트로 변경하였습니다.

@SpringBootTest
@EnableAutoConfiguration
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class PostServiceTotalTest {
    @Autowired
    private PostService postService;

    @Autowired
    private PostRepository postRepository;

    public PostDTO initPostDTO() {
        return PostDTO.builder()
                .title("title")
                .contents("contents")
                .build();
    }

    public Post initPost(PostDTO postDTO) {
        return Post.builder()
                .title(postDTO.getTitle())
                .contents(postDTO.getContents())
                .createAt(LocalDateTime.now())
                .build();
    }

    @Test
    @DisplayName("게시물 등록하기 테스트")
    @Order(1)
    public void createPost() throws Exception {
        //given
        PostDTO postDTO = initPostDTO();

        // when
        PostDTO post1 = postService.createPost(postDTO);

        // then
        assertThat(post1.getId()).isEqualTo(1L);
    }

    @Test
    @Order(2)
    public void 게시물_조회() throws Exception {
        // when
        PostDTO post = postService.getPost(1L);

        // then
        assertThat(post.getId()).isEqualTo(1L);
        assertThat(post.getTitle()).isEqualTo("title");
        assertThat(post.getContents()).isEqualTo("contents");
    }

    @Test
    @Order(3)
    @Transactional
    public void 게시물_제목_업데이트() throws Exception {
        Post findPost = postRepository.findById(1L).get();

        findPost.changeTitle("title update");

        Post updatePost = postRepository.save(findPost);

        assertThat(updatePost.getId()).isEqualTo(findPost.getId());
        assertThat(updatePost.getTitle()).isEqualTo("title update");
        assertThat(updatePost.getContents()).isEqualTo("contents");
    }

    @Test
    @Order(4)
    @Transactional
    public void 게시물_내용_업데이트() throws Exception {
        Post findPost = postRepository.findById(1L).get();

        findPost.changeContents("contents update");

        Post updatePost = postRepository.save(findPost);

        assertThat(updatePost.getId()).isEqualTo(findPost.getId());
        assertThat(updatePost.getTitle()).isEqualTo("title");
        assertThat(updatePost.getContents()).isEqualTo("contents update");
    }

    @Test
    @Transactional
    public void 게시물_삭제_성공() throws Exception {
        Post post = postRepository.findById(1L).get();

        postRepository.delete(post);

        assertThatThrownBy(() -> {
            postService.getPost(1L);
        }).isInstanceOf(PostNotFound.class)
                .hasMessage("해당 포스트가 존재하지 않습니다.");
    }
}

+ Recent posts