전체 코드는 여기에서 볼 수 있습니다.
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("해당 포스트가 존재하지 않습니다.");
}
}
'스프링 부트' 카테고리의 다른 글
스프링부트 게시판 API 만들기 - 7 (게시물 카테고리 적용하기) (0) | 2021.04.27 |
---|---|
스프링부트 게시판 API 만들기 - 6 (Spring Security를 사용하여 Json로그인 하기) (0) | 2021.04.25 |
스프링부트 게시판 API 만들기 - 4 (게시글 수정, 삭제 테스트 코드 작성) (0) | 2021.04.23 |
스프링부트 게시판 API 만들기 - 3 (게시글 수정, 삭제 코드 작성) (0) | 2021.04.22 |
스프링부트 게시판 API 만들기 - 1 (환경 설정, 게시물 가져오기, 게시물 등록하기) (0) | 2021.04.21 |