#16 board : article add, update, delete impl
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
package com.example.board.controller;
|
||||
|
||||
import com.example.board.domain.type.SearchType;
|
||||
import com.example.board.domain.constant.FormStatus;
|
||||
import com.example.board.domain.constant.SearchType;
|
||||
import com.example.board.dto.UserAccountDto;
|
||||
import com.example.board.dto.request.ArticleRequest;
|
||||
import com.example.board.dto.response.ArticleResponse;
|
||||
import com.example.board.dto.response.ArticleWithCommentsResponse;
|
||||
import com.example.board.service.ArticleService;
|
||||
@@ -12,10 +15,7 @@ import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.web.PageableDefault;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -45,14 +45,15 @@ public class ArticleController {
|
||||
|
||||
@GetMapping("/{articleId}")
|
||||
public String article(@PathVariable Long articleId, ModelMap map) {
|
||||
ArticleWithCommentsResponse article = ArticleWithCommentsResponse.from(articleService.getArticle(articleId));
|
||||
ArticleWithCommentsResponse article = ArticleWithCommentsResponse.from(articleService.getArticleWithComments(articleId));
|
||||
map.addAttribute("article", article);
|
||||
map.addAttribute("articleComments", article.articleCommentsResponse());
|
||||
map.addAttribute("totalCount", articleService.getArticleCount());
|
||||
return "articles/detail";
|
||||
}
|
||||
|
||||
@GetMapping("/search-hashtag")
|
||||
public String searchHashtag(
|
||||
public String searchArticleHashtag(
|
||||
@RequestParam(required = false) SearchType searchType,
|
||||
@RequestParam(required = false) String searchValue,
|
||||
@PageableDefault(size = 10, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable,
|
||||
@@ -69,4 +70,49 @@ public class ArticleController {
|
||||
|
||||
return "articles/search-hashtag";
|
||||
}
|
||||
|
||||
@GetMapping("/form")
|
||||
public String articleForm(ModelMap map) {
|
||||
map.addAttribute("formStatus", FormStatus.CREATE);
|
||||
|
||||
return "articles/form";
|
||||
}
|
||||
|
||||
@PostMapping ("/form")
|
||||
public String postNewArticle(ArticleRequest articleRequest) {
|
||||
// TODO: 인증 정보를 넣어줘야 한다.
|
||||
articleService.saveArticle(articleRequest.toDto(UserAccountDto.of(
|
||||
"bobby", "asdf1234", "bobby@mail.com", "bobby", "memo"
|
||||
)));
|
||||
|
||||
return "redirect:/articles";
|
||||
}
|
||||
|
||||
@GetMapping("/{articleId}/form")
|
||||
public String updateArticleForm(@PathVariable Long articleId, ModelMap map) {
|
||||
ArticleResponse article = ArticleResponse.from(articleService.getArticle(articleId));
|
||||
|
||||
map.addAttribute("article", article);
|
||||
map.addAttribute("formStatus", FormStatus.UPDATE);
|
||||
|
||||
return "articles/form";
|
||||
}
|
||||
|
||||
@PostMapping ("/{articleId}/form")
|
||||
public String updateArticle(@PathVariable Long articleId, ArticleRequest articleRequest) {
|
||||
// TODO: 인증 정보를 넣어줘야 한다.
|
||||
articleService.updateArticle(articleId, articleRequest.toDto(UserAccountDto.of(
|
||||
"bobby", "asdf1234", "bobby@mail.com", "bobby", "memo", null, null, null, null
|
||||
)));
|
||||
|
||||
return "redirect:/articles/" + articleId;
|
||||
}
|
||||
|
||||
@PostMapping ("/{articleId}/delete")
|
||||
public String deleteArticle(@PathVariable Long articleId) {
|
||||
// TODO: 인증 정보를 넣어줘야 한다.
|
||||
articleService.deleteArticle(articleId);
|
||||
|
||||
return "redirect:/articles";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ public class UserAccount extends AuditingFields {
|
||||
@Setter
|
||||
@Column(length = 100)
|
||||
private String email;
|
||||
|
||||
@Setter
|
||||
@Column(length = 100)
|
||||
private String nickname;
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.example.board.domain.constant;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
public enum FormStatus {
|
||||
CREATE("저장", false),
|
||||
UPDATE("수정", true);
|
||||
|
||||
@Getter private final String description;
|
||||
@Getter private final Boolean update;
|
||||
|
||||
FormStatus(String description, Boolean update) {
|
||||
this.description = description;
|
||||
this.update = update;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.example.board.domain.type;
|
||||
package com.example.board.domain.constant;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.example.board.dto;
|
||||
|
||||
import com.example.board.domain.Article;
|
||||
import com.example.board.domain.UserAccount;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@@ -15,6 +16,11 @@ public record ArticleDto(
|
||||
LocalDateTime modifiedAt,
|
||||
String modifiedBy
|
||||
) {
|
||||
|
||||
public static ArticleDto of(UserAccountDto userAccountDto, String title, String content, String hashtag) {
|
||||
return new ArticleDto(null, userAccountDto, title, content, hashtag, null, null, null, null);
|
||||
}
|
||||
|
||||
public static ArticleDto of(Long id, UserAccountDto userAccountDto, String title, String content, String hashtag, LocalDateTime createdAt, String createdBy, LocalDateTime modifiedAt, String modifiedBy) {
|
||||
return new ArticleDto(id, userAccountDto, title, content, hashtag, createdAt, createdBy, modifiedAt, modifiedBy);
|
||||
}
|
||||
@@ -33,9 +39,9 @@ public record ArticleDto(
|
||||
);
|
||||
}
|
||||
|
||||
public Article toEntity() {
|
||||
public Article toEntity(UserAccount userAccount) {
|
||||
return Article.of(
|
||||
userAccountDto.toEntity(),
|
||||
userAccount,
|
||||
title,
|
||||
content,
|
||||
hashtag
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.example.board.dto.request;
|
||||
|
||||
import com.example.board.dto.ArticleDto;
|
||||
import com.example.board.dto.UserAccountDto;
|
||||
|
||||
public record ArticleRequest(
|
||||
String title,
|
||||
String content,
|
||||
String hashtag
|
||||
) {
|
||||
|
||||
public static ArticleRequest of(String title, String content, String hashtag) {
|
||||
return new ArticleRequest(title, content, hashtag);
|
||||
}
|
||||
|
||||
public ArticleDto toDto(UserAccountDto userAccountDto) {
|
||||
return ArticleDto.of(
|
||||
userAccountDto,
|
||||
title,
|
||||
content,
|
||||
hashtag
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,5 +3,5 @@ package com.example.board.repository;
|
||||
import com.example.board.domain.UserAccount;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface UserAccountRepository extends JpaRepository<UserAccount, Long> {
|
||||
public interface UserAccountRepository extends JpaRepository<UserAccount, String> {
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
package com.example.board.service;
|
||||
|
||||
import com.example.board.domain.Article;
|
||||
import com.example.board.domain.type.SearchType;
|
||||
import com.example.board.domain.UserAccount;
|
||||
import com.example.board.domain.constant.SearchType;
|
||||
import com.example.board.dto.ArticleDto;
|
||||
import com.example.board.dto.ArticleWithCommentsDto;
|
||||
import com.example.board.repository.ArticleRepository;
|
||||
import com.example.board.repository.UserAccountRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.domain.Page;
|
||||
@@ -22,6 +24,7 @@ import java.util.List;
|
||||
public class ArticleService {
|
||||
|
||||
private final ArticleRepository articleRepository;
|
||||
private final UserAccountRepository userAccountRepository;
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Page<ArticleDto> searchArticles(SearchType searchType, String searchKeyword, Pageable pageable) {
|
||||
@@ -39,28 +42,29 @@ public class ArticleService {
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public ArticleWithCommentsDto getArticle(Long articleId) {
|
||||
public ArticleWithCommentsDto getArticleWithComments(Long articleId) {
|
||||
return articleRepository.findById(articleId)
|
||||
.map(ArticleWithCommentsDto::from)
|
||||
.orElseThrow(() -> new EntityNotFoundException("게시글이 없습니다 - articleId: " + articleId));
|
||||
}
|
||||
|
||||
public void saveArticle(ArticleDto dto) {
|
||||
articleRepository.save(dto.toEntity());
|
||||
@Transactional(readOnly = true)
|
||||
public ArticleDto getArticle(Long articleId) {
|
||||
return articleRepository.findById(articleId)
|
||||
.map(ArticleDto::from)
|
||||
.orElseThrow(() -> new EntityNotFoundException("게시글이 없습니다 - articleId: " + articleId));
|
||||
}
|
||||
|
||||
public void updateArticle(ArticleDto dto) {
|
||||
public void saveArticle(ArticleDto dto) {
|
||||
UserAccount userAccount = userAccountRepository.getReferenceById(dto.userAccountDto().userId());
|
||||
articleRepository.save(dto.toEntity(userAccount));
|
||||
}
|
||||
|
||||
public void updateArticle(Long articleId, ArticleDto dto) {
|
||||
try {
|
||||
Article article = articleRepository.getReferenceById(dto.id());
|
||||
|
||||
if (dto.title() != null) {
|
||||
article.setTitle(dto.title());
|
||||
}
|
||||
|
||||
if (dto.content() != null) {
|
||||
article.setContent(dto.content());
|
||||
}
|
||||
|
||||
Article article = articleRepository.getReferenceById(articleId);
|
||||
if (dto.title() != null) { article.setTitle(dto.title()); }
|
||||
if (dto.content() != null) { article.setContent(dto.content()); }
|
||||
article.setHashtag(dto.hashtag());
|
||||
} catch (EntityNotFoundException e) {
|
||||
log.warn("게시글 업데이트 실패. 게시글을 찾을 수 없습니다 - dto: {}", dto);
|
||||
@@ -82,4 +86,8 @@ public class ArticleService {
|
||||
public List<String> getHashtags() {
|
||||
return articleRepository.findAllDistinctHashtags();
|
||||
}
|
||||
|
||||
public long getArticleCount() {
|
||||
return articleRepository.count();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
package com.example.board.controller;
|
||||
|
||||
import com.example.board.config.SecurityConfig;
|
||||
import com.example.board.domain.type.SearchType;
|
||||
import com.example.board.domain.constant.FormStatus;
|
||||
import com.example.board.domain.constant.SearchType;
|
||||
import com.example.board.dto.ArticleDto;
|
||||
import com.example.board.dto.ArticleWithCommentsDto;
|
||||
import com.example.board.dto.UserAccountDto;
|
||||
import com.example.board.dto.request.ArticleRequest;
|
||||
import com.example.board.dto.response.ArticleResponse;
|
||||
import com.example.board.service.ArticleService;
|
||||
import com.example.board.service.PaginationService;
|
||||
import com.example.board.util.FormDataEncoder;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -25,15 +30,18 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.mockito.BDDMockito.*;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
@DisplayName("View 컨트롤러 - 게시글")
|
||||
@Import(SecurityConfig.class)
|
||||
@Import({SecurityConfig.class, FormDataEncoder.class})
|
||||
@WebMvcTest(ArticleController.class)
|
||||
class ArticleControllerTest {
|
||||
|
||||
private final MockMvc mockMvc;
|
||||
private final FormDataEncoder formDataEncoder;
|
||||
|
||||
@MockBean
|
||||
private ArticleService articleService;
|
||||
@@ -41,8 +49,12 @@ class ArticleControllerTest {
|
||||
@MockBean
|
||||
private PaginationService paginationService;
|
||||
|
||||
public ArticleControllerTest(@Autowired MockMvc mockMvc) {
|
||||
public ArticleControllerTest(
|
||||
@Autowired MockMvc mockMvc,
|
||||
@Autowired FormDataEncoder formDataEncoder
|
||||
) {
|
||||
this.mockMvc = mockMvc;
|
||||
this.formDataEncoder = formDataEncoder;
|
||||
}
|
||||
|
||||
@DisplayName("[view][GET] 게시글 리스트(게시판) 페이지 - 정상 호출")
|
||||
@@ -126,8 +138,9 @@ class ArticleControllerTest {
|
||||
public void givenNothing_whenRequestingArticleView_thenReturnsArticleView() throws Exception {
|
||||
// given
|
||||
Long articleId = 1L;
|
||||
long totalCount = 1L;
|
||||
|
||||
given(articleService.getArticle(articleId)).willReturn(createArticleWithCommentDto());
|
||||
given(articleService.getArticleWithComments(articleId)).willReturn(createArticleWithCommentDto());
|
||||
|
||||
// when & then
|
||||
mockMvc.perform(get("/articles/" + articleId))
|
||||
@@ -138,7 +151,8 @@ class ArticleControllerTest {
|
||||
.andExpect(model().attributeExists("articleComments"))
|
||||
;
|
||||
|
||||
then(articleService).should().getArticle(articleId);
|
||||
then(articleService).should().getArticleWithComments(articleId);
|
||||
then(articleService).should().getArticleCount();
|
||||
}
|
||||
|
||||
@Disabled("구현 중")
|
||||
@@ -208,6 +222,107 @@ class ArticleControllerTest {
|
||||
then(paginationService).should().getPaginationBarNumbers(anyInt(), anyInt());
|
||||
}
|
||||
|
||||
@DisplayName("[view][GET] 새 게시글 작성 페이지")
|
||||
@Test
|
||||
void givenNothing_whenRequesting_thenReturnsNewArticlePage() throws Exception {
|
||||
// Given
|
||||
|
||||
// When & Then
|
||||
mockMvc.perform(get("/articles/form"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML))
|
||||
.andExpect(view().name("articles/form"))
|
||||
.andExpect(model().attribute("formStatus", FormStatus.CREATE));
|
||||
}
|
||||
|
||||
@DisplayName("[view][POST] 새 게시글 등록 - 정상 호출")
|
||||
@Test
|
||||
void givenNewArticleInfo_whenRequesting_thenSavesNewArticle() throws Exception {
|
||||
// Given
|
||||
ArticleRequest articleRequest = ArticleRequest.of("new title", "new content", "#new");
|
||||
willDoNothing().given(articleService).saveArticle(any(ArticleDto.class));
|
||||
|
||||
// When & Then
|
||||
mockMvc.perform(
|
||||
post("/articles/form")
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.content(formDataEncoder.encode(articleRequest))
|
||||
.with(csrf())
|
||||
)
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andExpect(view().name("redirect:/articles"))
|
||||
.andExpect(redirectedUrl("/articles"));
|
||||
then(articleService).should().saveArticle(any(ArticleDto.class));
|
||||
}
|
||||
|
||||
@DisplayName("[view][GET] 게시글 수정 페이지")
|
||||
@Test
|
||||
void givenNothing_whenRequesting_thenReturnsUpdatedArticlePage() throws Exception {
|
||||
// Given
|
||||
long articleId = 1L;
|
||||
ArticleDto dto = createArticleDto();
|
||||
given(articleService.getArticle(articleId)).willReturn(dto);
|
||||
|
||||
// When & Then
|
||||
mockMvc.perform(get("/articles/" + articleId + "/form"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML))
|
||||
.andExpect(view().name("articles/form"))
|
||||
.andExpect(model().attribute("article", ArticleResponse.from(dto)))
|
||||
.andExpect(model().attribute("formStatus", FormStatus.UPDATE));
|
||||
then(articleService).should().getArticle(articleId);
|
||||
}
|
||||
|
||||
@DisplayName("[view][POST] 게시글 수정 - 정상 호출")
|
||||
@Test
|
||||
void givenUpdatedArticleInfo_whenRequesting_thenUpdatesNewArticle() throws Exception {
|
||||
// Given
|
||||
long articleId = 1L;
|
||||
ArticleRequest articleRequest = ArticleRequest.of("new title", "new content", "#new");
|
||||
willDoNothing().given(articleService).updateArticle(eq(articleId), any(ArticleDto.class));
|
||||
|
||||
// When & Then
|
||||
mockMvc.perform(
|
||||
post("/articles/" + articleId + "/form")
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.content(formDataEncoder.encode(articleRequest))
|
||||
.with(csrf())
|
||||
)
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andExpect(view().name("redirect:/articles/" + articleId))
|
||||
.andExpect(redirectedUrl("/articles/" + articleId));
|
||||
then(articleService).should().updateArticle(eq(articleId), any(ArticleDto.class));
|
||||
}
|
||||
|
||||
@DisplayName("[view][POST] 게시글 삭제 - 정상 호출")
|
||||
@Test
|
||||
void givenArticleIdToDelete_whenRequesting_thenDeletesArticle() throws Exception {
|
||||
// Given
|
||||
long articleId = 1L;
|
||||
willDoNothing().given(articleService).deleteArticle(articleId);
|
||||
|
||||
// When & Then
|
||||
mockMvc.perform(
|
||||
post("/articles/" + articleId + "/delete")
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.with(csrf())
|
||||
)
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andExpect(view().name("redirect:/articles"))
|
||||
.andExpect(redirectedUrl("/articles"));
|
||||
then(articleService).should().deleteArticle(articleId);
|
||||
}
|
||||
|
||||
|
||||
private ArticleDto createArticleDto() {
|
||||
return ArticleDto.of(
|
||||
createUserAccountDto(),
|
||||
"title",
|
||||
"content",
|
||||
"#java"
|
||||
);
|
||||
}
|
||||
|
||||
private ArticleWithCommentsDto createArticleWithCommentDto() {
|
||||
return ArticleWithCommentsDto.of(
|
||||
1L,
|
||||
|
||||
@@ -2,11 +2,12 @@ package com.example.board.service;
|
||||
|
||||
import com.example.board.domain.Article;
|
||||
import com.example.board.domain.UserAccount;
|
||||
import com.example.board.domain.type.SearchType;
|
||||
import com.example.board.domain.constant.SearchType;
|
||||
import com.example.board.dto.ArticleDto;
|
||||
import com.example.board.dto.ArticleWithCommentsDto;
|
||||
import com.example.board.dto.UserAccountDto;
|
||||
import com.example.board.repository.ArticleRepository;
|
||||
import com.example.board.repository.UserAccountRepository;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@@ -15,6 +16,7 @@ import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import javax.persistence.EntityNotFoundException;
|
||||
import java.time.LocalDateTime;
|
||||
@@ -35,6 +37,9 @@ class ArticleServiceTest {
|
||||
@Mock
|
||||
private ArticleRepository articleRepository;
|
||||
|
||||
@Mock
|
||||
private UserAccountRepository userAccountRepository;
|
||||
|
||||
@DisplayName("검색어 없이 게시글을 검색하면, 게시글 페이지를 반환한다.")
|
||||
@Test
|
||||
void givenNoSearchParameters_whenSearchingArticles_thenReturnsArticlePage() {
|
||||
@@ -97,16 +102,16 @@ class ArticleServiceTest {
|
||||
then(articleRepository).should().findByHashtag(hashtag, pageable);
|
||||
}
|
||||
|
||||
@DisplayName("게시글을 조회하면 게시글을 반환한다.")
|
||||
@DisplayName("게시글 ID로 조회하면, 댓글 달긴 게시글을 반환한다.")
|
||||
@Test
|
||||
void givenArticleId_whenSearchingArticle_thenReturnArticle() {
|
||||
// given
|
||||
void givenArticleId_whenSearchingArticleWithComments_thenReturnsArticleWithComments() {
|
||||
// Given
|
||||
Long articleId = 1L;
|
||||
Article article = createArticle();
|
||||
given(articleRepository.findById(articleId)).willReturn(Optional.of(article));
|
||||
|
||||
// When
|
||||
ArticleWithCommentsDto dto = sut.getArticle(articleId);
|
||||
ArticleWithCommentsDto dto = sut.getArticleWithComments(articleId);
|
||||
|
||||
// Then
|
||||
assertThat(dto)
|
||||
@@ -116,7 +121,43 @@ class ArticleServiceTest {
|
||||
then(articleRepository).should().findById(articleId);
|
||||
}
|
||||
|
||||
@DisplayName("없는 게시글을 조회하면, 예외를 던진다.")
|
||||
@DisplayName("댓글 달린 게시글이 없으면, 예외를 던진다.")
|
||||
@Test
|
||||
void givenNonexistentArticleId_whenSearchingArticleWithComments_thenThrowsException() {
|
||||
// Given
|
||||
Long articleId = 0L;
|
||||
given(articleRepository.findById(articleId)).willReturn(Optional.empty());
|
||||
|
||||
// When
|
||||
Throwable t = catchThrowable(() -> sut.getArticleWithComments(articleId));
|
||||
|
||||
// Then
|
||||
assertThat(t)
|
||||
.isInstanceOf(EntityNotFoundException.class)
|
||||
.hasMessage("게시글이 없습니다 - articleId: " + articleId);
|
||||
then(articleRepository).should().findById(articleId);
|
||||
}
|
||||
|
||||
@DisplayName("게시글을 조회하면 게시글을 반환한다.")
|
||||
@Test
|
||||
void givenArticleId_whenSearchingArticle_thenReturnArticle() {
|
||||
// given
|
||||
Long articleId = 1L;
|
||||
Article article = createArticle();
|
||||
given(articleRepository.findById(articleId)).willReturn(Optional.of(article));
|
||||
|
||||
// When
|
||||
ArticleDto dto = sut.getArticle(articleId);
|
||||
|
||||
// Then
|
||||
assertThat(dto)
|
||||
.hasFieldOrPropertyWithValue("title", article.getTitle())
|
||||
.hasFieldOrPropertyWithValue("content", article.getContent())
|
||||
.hasFieldOrPropertyWithValue("hashtag", article.getHashtag());
|
||||
then(articleRepository).should().findById(articleId);
|
||||
}
|
||||
|
||||
@DisplayName("게시글이 없으면, 예외를 던진다.")
|
||||
@Test
|
||||
void givenNonexistentArticleId_whenSearchingArticle_thenThrowsException() {
|
||||
// Given
|
||||
@@ -124,7 +165,7 @@ class ArticleServiceTest {
|
||||
given(articleRepository.findById(articleId)).willReturn(Optional.empty());
|
||||
|
||||
// When
|
||||
Throwable t = catchThrowable(() -> sut.getArticle(articleId));
|
||||
Throwable t = catchThrowable(() -> sut.getArticleWithComments(articleId));
|
||||
|
||||
// Then
|
||||
assertThat(t)
|
||||
@@ -138,13 +179,15 @@ class ArticleServiceTest {
|
||||
void givenArticleInfo_whenSavingArticle_thenSavesArticle() {
|
||||
// given
|
||||
ArticleDto dto = createArticleDto();
|
||||
given(articleRepository.save(any(Article.class))).willReturn(createArticle());
|
||||
|
||||
given(userAccountRepository.getReferenceById(dto.userAccountDto().userId())).willReturn(createUserAccount());
|
||||
given(articleRepository.save(any(Article.class))).willReturn(createArticle());
|
||||
|
||||
// when
|
||||
sut.saveArticle(dto);
|
||||
|
||||
// then
|
||||
then(userAccountRepository).should().getReferenceById(dto.userAccountDto().userId());
|
||||
then(articleRepository).should().save(any(Article.class));
|
||||
}
|
||||
|
||||
@@ -157,7 +200,7 @@ class ArticleServiceTest {
|
||||
given(articleRepository.getReferenceById(dto.id())).willReturn(article);
|
||||
|
||||
// when
|
||||
sut.updateArticle(dto);
|
||||
sut.updateArticle(dto.id(), dto);
|
||||
|
||||
// then
|
||||
assertThat(article)
|
||||
@@ -175,7 +218,7 @@ class ArticleServiceTest {
|
||||
given(articleRepository.getReferenceById(dto.id())).willThrow(EntityNotFoundException.class);
|
||||
|
||||
// When
|
||||
sut.updateArticle(dto);
|
||||
sut.updateArticle(dto.id(), dto);
|
||||
|
||||
// Then
|
||||
then(articleRepository).should().getReferenceById(dto.id());
|
||||
@@ -221,12 +264,15 @@ class ArticleServiceTest {
|
||||
}
|
||||
|
||||
private Article createArticle() {
|
||||
return Article.of(
|
||||
Article article = Article.of(
|
||||
createUserAccount(),
|
||||
"title",
|
||||
"content",
|
||||
"#java"
|
||||
);
|
||||
ReflectionTestUtils.setField(article, "id", 1L);
|
||||
|
||||
return article;
|
||||
}
|
||||
|
||||
private ArticleDto createArticleDto() {
|
||||
@@ -234,7 +280,8 @@ class ArticleServiceTest {
|
||||
}
|
||||
|
||||
private ArticleDto createArticleDto(String title, String content, String hashtag) {
|
||||
return ArticleDto.of(1L,
|
||||
return ArticleDto.of(
|
||||
1L,
|
||||
createUserAccountDto(),
|
||||
title,
|
||||
content,
|
||||
|
||||
Reference in New Issue
Block a user