Spring Boot 게시판 만들기 3 - 게시글 작성하기

3. 새로운 Post 생성 요청 처리하기

데이터를 저장하는 로직은 DB에 접근을 하기 때문에 다음과 같은 로직을 추가해 DB에 데이터들이 제대로 저장되는지 확인한다. 어플리케이션을 실핸한 후 http://localhost:8080/h2-console 를 통해 데이터 베이스에 접근할 수 있다.

application.yml

spring:
h2:
console:
enabled: true
path: /h2-console
datasource:
username: sa
password:
url: jdbc:h2:mem:testdb
driver-class-name: org.h2.Driver

/post경로로 post 요청이 들어올 경우 입력된 정보들이 제대로 들어왔는지 Validation을 진행하고 문제가 없을 경우 데이터를 저장한다.

PostController.java

@PostMapping("/post")
public String creatNewPost(@Valid @ModelAttribute("postDto") PostDto postDto) {
postService.addPost(postDto);

return "redirect:/";
}

생성 요청 테스트 코드 작성하기

MockBean 추가하기

PostController의 creatNewPost메소드 내에서는 PostService객체를 사용하기 때문에 테스트코드를 작성하기 위해서 해당 Mock 을 추가해줄 필요가 있다.

PostControllerTest.java

@MockBean
private PostService postService;

PostService객체의 MockBean을 생성해주지 않으면 아래와 같은 오류로 테스트가 진행되지 않는다.

creatNewPost메소드 /post경로로 post 요청에 대한 테스트 코드를 작성할 것이다.

  • given메소드를 이용해 PostService가 반환할 객체에 대해 정의를 한다.
  • /post경로로 post요청을 보내도록한다.
  • 데이터를 보내기 위해서는 flashAttr 메소드를 이용해 플래시 스코프에 객체를 설정하도록한다.
  • 요청이 완료된 후 리다이렉션(Status Code : 302) 이 제대로 이루어지는지 확인한다.

PostControllerTest.java

@Test
@DisplayName("새로운 게시글 생성을 성공한다.")
public void successCreateNewPost() throws Exception {
Post mockPost = Post.builder()
.id(1L)
.title("test")
.name("tester")
.content("test")
.writeTime(LocalDateTime.now())
.build();

given(postService.addPost(any())).willReturn(mockPost);

ResultActions resultActions = mockMvc.perform(post("/post")
.flashAttr("postDto", new PostDto())
// .sessionAttr("postDto", new PostDto())
.param("title", "test")
.param("name", "tester")
.param("content", "test")
);

resultActions
.andExpect(status().is3xxRedirection())
// Response Header에 있는 Location 정보를 비교한다.
.andDo(print());

verify(postService).addPost(any());
}

실패에 대한 테스트 코드 진행

Controller단에서의 Data Validation이 제대로 작동하는지 확인하기 위한 테스트 코드들이다. title, name, content 에 대한 값의 검증을 해줘야 하기 때문에 세가지 경우로 확인했다.

PostControllerTest.java

@Test
@DisplayName("새로운 게시글 생성을 실패한다.")
public void failCreateNewFailWithNoTitle() throws Exception {
Post mockPost = Post.builder()
.id(1L)
.title("test")
.name("tester")
.content("test")
.writeTime(LocalDateTime.now())
.build();

given(postService.addPost(any())).willReturn(mockPost);

ResultActions resultActions = mockMvc.perform(post("/post")
.flashAttr("postDto", new PostDto())
.param("name", "tester")
.param("content", "test")
);

resultActions
.andExpect(status().isBadRequest())
.andDo(print());
}

@Test
@DisplayName("새로운 게시글 생성을 실패한다.")
public void failCreateNewFailWithNoName() throws Exception {
Post mockPost = Post.builder()
.id(1L)
.title("test")
.name("tester")
.content("test")
.writeTime(LocalDateTime.now())
.build();

given(postService.addPost(any())).willReturn(mockPost);

ResultActions resultActions = mockMvc.perform(post("/post")
.flashAttr("postDto", new PostDto())
.param("title", "test")
.param("content", "test")
);

resultActions
.andExpect(status().isBadRequest())
.andDo(print());
}

@Test
@DisplayName("새로운 게시글 생성을 실패한다.")
public void failCreateNewFailWithNoContent() throws Exception {
Post mockPost = Post.builder()
.id(1L)
.title("test")
.name("tester")
.content("test")
.writeTime(LocalDateTime.now())
.build();

given(postService.addPost(any())).willReturn(mockPost);

ResultActions resultActions = mockMvc.perform(post("/post")
.flashAttr("postDto", new PostDto())
.param("title", "test")
.param("name", "tester")
);

resultActions
.andExpect(status().isBadRequest())
.andDo(print());
}

데이터 저장하기

PostRepository 객체를 통해 데이터 저장을 진행한다.

PostService.java

@Service
@RequiredArgsConstructor
public class PostService {
private final PostRepository postRepository;

@Transactional
public Post addPost(PostDto postDto) {
Post post = Post.builder()
.title(postDto.getTitle())
.name(postDto.getName())
.content(postDto.getContent())
.writeTime(LocalDateTime.now())
.build();

return postRepository.save(post);
}
}

저장로직에 대한 테스트 코드 작성

PostService 객체의 addPost가 실행된 후 값이 제대로 반환됐는지 확인한 후 PostRepository 객체에서 save 메소드가 호출됐는지 확인한다.

PostServiceTest.java

class PostServiceTest {

@Mock
private PostRepository postRepository;

private PostService postService;

@BeforeEach
public void init() {
MockitoAnnotations.openMocks(this);

postService = new PostService(postRepository);
}

@Test
@DisplayName("새로운 포스트를 추가한다.")
@Transactional
public void addPost() {
PostDto postDto = PostDto.builder()
.title("test")
.name("tester")
.content("test")
.writeTime(LocalDateTime.now())
.build();

Post mockPost = Post.builder()
.id(1L)
.title("test")
.name("tester")
.content("test")
.writeTime(LocalDateTime.now())
.build();

given(postRepository.save(any())).willReturn(mockPost);

Post returnPost = postService.addPost(postDto);

assertThat(returnPost.getId()).isEqualTo(mockPost.getId());
assertThat(returnPost.getTitle()).isEqualTo(mockPost.getTitle());
assertThat(returnPost.getName()).isEqualTo(mockPost.getName());
assertThat(returnPost.getContent()).isEqualTo(mockPost.getContent());
assertThat(returnPost.getWriteTime()).isEqualTo(mockPost.getWriteTime());


verify(postRepository).save(any());
}
}
Share