유저계정이 추가됨에 따라, 게시판, 게시글 테스트를 재 정의 하였다.
//ArticleTest.java
package com.fastcampus.projectboard.service;
import com.fastcampus.projectboard.domain.Article;
import com.fastcampus.projectboard.domain.UserAccount;
import com.fastcampus.projectboard.domain.type.SearchType;
import com.fastcampus.projectboard.dto.ArticleDto;
import com.fastcampus.projectboard.dto.ArticleWithCommentsDto;
import com.fastcampus.projectboard.dto.UserAccountDto;
import com.fastcampus.projectboard.repository.ArticleRepository;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import javax.persistence.EntityNotFoundException;
import java.time.LocalDateTime;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.*;
@DisplayName("비즈니스 로직 - 게시글")
@ExtendWith(MockitoExtension.class)
class ArticleServiceTest {
@InjectMocks
private ArticleService sut;
@Mock
private ArticleRepository articleRepository;
@DisplayName("검색어 없이 게시글을 검색하면, 게시글 페이지를 반환한다.")
@Test
void givenNoSearchParameters_whenSearchingArticles_thenReturnsArticlePage() {
// Given
Pageable pageable = Pageable.ofSize(20);
given(articleRepository.findAll(pageable)).willReturn(Page.empty());
// When
Page<ArticleDto> articles = sut.searchArticles(null, null, pageable);
// Then
assertThat(articles).isEmpty();
then(articleRepository).should().findAll(pageable);
}
@DisplayName("검색어와 함께 게시글을 검색하면, 게시글 페이지를 반환한다.")
@Test
void givenSearchParameters_whenSearchingArticles_thenReturnsArticlePage() {
//Given
SearchType searchType = SearchType.TITLE;
String searchKeyword = "title";
Pageable pageable = Pageable.ofSize(20);
given(articleRepository.findByTitle(searchKeyword, pageable)).willReturn(Page.empty());
// When
Page<ArticleDto> articles = sut.searchArticles(searchType, searchKeyword, pageable);
// Then
assertThat(articles).isEmpty();
then(articleRepository).should().findByTitle(searchKeyword, pageable);
}
@DisplayName("게시글을 조회하면, 게시글을 반환한다.")
@Test
void givenArticleId_whenSearchingArticle_thenReturnsArticle() {
// Given
Long articleId = 1L;
Article article = createArticle();
given(articleRepository.findById(articleId)).willReturn(Optional.of(article));
// When
ArticleWithCommentsDto 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
Long articleId = 0L;
given(articleRepository.findById(articleId)).willReturn(Optional.empty());
// When
Throwable t = catchThrowable(() -> sut.getArticle(articleId));
// Then
assertThat(t)
.isInstanceOf(EntityNotFoundException.class)
.hasMessage("게시글이 없습니다 - articleId: " + articleId);
then(articleRepository).should().findById(articleId);
}
@DisplayName("게시글 정보를 입력하면, 게시글을 생성한다")
@Test
void givenArticleInfo_whenSavingArticle_thenSavesArticle() {
// Given
ArticleDto dto = createArticleDto();
given(articleRepository.save(any(Article.class))).willReturn(createArticle());
// When
sut.saveArticle(dto);
// Then
then(articleRepository).should().save(any(Article.class));
}
@DisplayName("게시글의 수정 정보를 입력하면, 게시글을 수정한다")
@Test
void givenModifiedArticleInfo_whenUpdatingArticle_thenUpdatesArticle() {
// Given
Article article = createArticle();
ArticleDto dto = createArticleDto("새 타이틀", "새 내용", "#springboot");
given(articleRepository.getReferenceById(dto.id())).willReturn(article);
// When
sut.updateArticle(dto);
// Then
assertThat(article)
.hasFieldOrPropertyWithValue("title", dto.title())
.hasFieldOrPropertyWithValue("content", dto.content())
.hasFieldOrPropertyWithValue("hashtag", dto.hashtag());
then(articleRepository).should().getReferenceById(dto.id());
}
@DisplayName("없는 게시글의 수정 정보를 입력하면, 경고 로그를 찍고 아무것도 하지 않는다.")
@Test
void givenNonexistenArticleInfo_whenUpdatingArticle_thenLogWarningAndDoesNothing() {
// Given
ArticleDto dto = createArticleDto("새 타이틀", "새 내용", "#springboot");
given(articleRepository.getReferenceById(dto.id())).willThrow(EntityNotFoundException.class);
// When
sut.updateArticle(dto);
// Then
then(articleRepository).should().getReferenceById(dto.id());
}
@DisplayName("게시글의 ID를 입력하면, 게시글을 삭제한다")
@Test
void givenArticleId_whenDeletingArticle_thenDeletesArticle() {
// Given
Long articleId = 1L;
willDoNothing().given(articleRepository).deleteById(articleId);
// When
sut.deleteArticle(1L);
// Then
then(articleRepository).should().deleteById(articleId);
}
private UserAccount createUserAccount() {
return UserAccount.of(
"taeho",
"password",
"ice_98@email.com",
"taeho",
null
);
}
private Article createArticle() {
return Article.of(createUserAccount(), "title", "content", "#java");
}
private ArticleDto createArticleDto() {
return createArticleDto("title", "content", "#java");
}
private ArticleDto createArticleDto(String title, String content, String hashtag) {
return ArticleDto.of(1L, createUserAccountDto(), title, content, hashtag, LocalDateTime.now(), "taeho", LocalDateTime.now(), "taeho");
}
private UserAccountDto createUserAccountDto() {
return UserAccountDto.of(
1L, "taeho", "password", "ice_98@mail.com", "ttaho", "this is memo", LocalDateTime.now(), "taeho", LocalDateTime.now(), "taeho");
}
}
//ArticleCommentTest.java
package com.fastcampus.projectboard.service;
import com.fastcampus.projectboard.domain.Article;
import com.fastcampus.projectboard.domain.ArticleComment;
import com.fastcampus.projectboard.domain.UserAccount;
import com.fastcampus.projectboard.dto.ArticleCommentDto;
import com.fastcampus.projectboard.dto.UserAccountDto;
import com.fastcampus.projectboard.repository.ArticleCommentRepository;
import com.fastcampus.projectboard.repository.ArticleRepository;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.BDDMockito;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import javax.persistence.EntityNotFoundException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.*;
@DisplayName("비즈니스 로직 - 댓글")
@ExtendWith(MockitoExtension.class)
class ArticleCommentServiceTest {
@InjectMocks
private ArticleCommentService sut;
@Mock
private ArticleRepository articleRepository;
@Mock
private ArticleCommentRepository articleCommentRepository;
@DisplayName("게시글 ID로 조회하면, 해당하는 댓글 리스트를 반환한다.")
@Test
void givenArticleId_whenSearchingArticleComments_thenReturnsArticleComments() {
// Given
Long articleId = 1L;
ArticleComment expected = createArticleComment("content");
given(articleCommentRepository.findByArticle_Id(articleId)).willReturn(List.of(expected));
// When
List<ArticleCommentDto> actual = sut.searchArticleComments(articleId);
// Then
assertThat(actual)
.hasSize(1)
.first().hasFieldOrPropertyWithValue("content", expected.getContent());
then(articleCommentRepository).should().findByArticle_Id(articleId);
}
@DisplayName("댓글 정보를 입력하면, 댓글을 저장한다.")
@Test
void givenArticleCommentInfo_whenSavingArticleComment_thenSavesArticleComment() {
// Given
ArticleCommentDto dto = createArticleCommentDto("댓글");
given(articleRepository.getReferenceById(dto.articleId())).willReturn(createArticle());
given(articleCommentRepository.save(any(ArticleComment.class))).willReturn(null);
// When
sut.saveArticleComment(dto);
// Then
then(articleRepository).should().getReferenceById(dto.articleId());
then(articleCommentRepository).should().save(any(ArticleComment.class));
}
@DisplayName("댓글 저장을 시도했는데 맞는 게시글이 없으면, 경고 로그를 찍고 아무것도 안한다.")
@Test
void givenNonexistentArticle_whenSavingArticleComment_thenLogsSituationAndDoesNothing() {
// Given
ArticleCommentDto dto = createArticleCommentDto("댓글");
given(articleRepository.getReferenceById(dto.articleId())).willThrow(EntityNotFoundException.class);
// When
sut.saveArticleComment(dto);
// Then
then(articleRepository).should().getReferenceById(dto.articleId());
then(articleCommentRepository).shouldHaveNoInteractions();
}
@DisplayName("댓글 정보를 입력하면, 댓글을 수정한다.")
@Test
void givenArticleCommentInfo_whenUpdatingArticleComment_thenUpdateArticleComment() {
// Given
String oldContent = "content";
String updatedContent = "댓글";
ArticleComment articleComment = createArticleComment(oldContent);
ArticleCommentDto dto = createArticleCommentDto(updatedContent);
given(articleCommentRepository.getReferenceById(dto.id())).willReturn(articleComment);
// When
sut.updateArticleComment(dto);
// Then
then(articleCommentRepository).should().getReferenceById(dto.id());
}
@DisplayName("없는 댓글 정보를 수정하려고 하면, 경고 로그를 찍고 아무것도 안한다.")
@Test
void givenNonexistentArticleComment_whenUpdatingArticleComment_thenLogsWarningAndDoesNothing() {
// Given
ArticleCommentDto dto = createArticleCommentDto("댓글");
given(articleCommentRepository.getReferenceById(dto.id())).willThrow(EntityNotFoundException.class);
// When
sut.updateArticleComment(dto);
// Then
then(articleCommentRepository).should().getReferenceById(dto.id());
}
@DisplayName("댓글 ID를 입력하면, 댓글을 삭제한다.")
@Test
void givenArticleCommentId_whenDeletingArticleComment_thenDeletesArticleComment() {
// Given
Long articleCommentId = 1L;
willDoNothing().given(articleCommentRepository).deleteById(articleCommentId);
// When
sut.deleteArticleComment(articleCommentId);
// Then
then(articleCommentRepository).should().deleteById(articleCommentId);
}
private ArticleCommentDto createArticleCommentDto(String content) {
return ArticleCommentDto.of(1L, 1L, createUserAccountDto(), content, LocalDateTime.now(), "taeho", LocalDateTime.now(), "taeho");
}
private UserAccountDto createUserAccountDto() {
return UserAccountDto.of(
1L, "taeho", "password", "ice_98@mail.com", "ttaho", "this is memo", LocalDateTime.now(), "taeho", LocalDateTime.now(), "taeho");
}
private ArticleComment createArticleComment(String content) {
return ArticleComment.of(Article.of(createUserAccount(), "title","content","hashtag"),createUserAccount(), content);
}
private UserAccount createUserAccount() {
return UserAccount.of(
"taeho",
"password",
"ice_98@email.com",
"taeho",
"memmem");
}
private Article createArticle() {
return Article.of(createUserAccount(), "title","content","#java");
}
}