Skip to content
Open
2 changes: 1 addition & 1 deletion MJS-BACK-SECURITY
11 changes: 11 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,17 @@ dependencies {
//Json parse
implementation 'org.json:json:20210307'

//FixtureMonkey core
testImplementation 'com.navercorp.fixturemonkey:fixture-monkey-starter:0.6.12'

// Jackson 기반 직렬화 지원 (DTO/Entity 생성 시 유용)
testImplementation 'com.navercorp.fixturemonkey:fixture-monkey-jackson:0.6.12'

// JUnit
testImplementation 'org.springframework.boot:spring-boot-starter-test'



}

test {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,15 @@

import nova.mjs.weeklyMenu.entity.WeeklyMenu;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

@Repository
public interface WeeklyMenuRepository extends JpaRepository<WeeklyMenu, Long> {

@Modifying
@Query(value = "TRUNCATE TABLE weekly_menu RESTART IDENTITY CASCADE", nativeQuery = true)
void truncateAllWithCascade();

}
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ private MenuCategory mapCategory(String category) {
//식단을 크롤링했을 때 중복 발생을 고려한 식단 데이터 삭제하는 메서드
@Transactional
public void deleteAllWeeklyMenus(){
menuRepository.deleteAll();
menuRepository.truncateAllWithCascade();
}

//DB에서 전체 식단 데이터를 가져오는 메서드
Expand Down
210 changes: 210 additions & 0 deletions src/test/java/nova/mjs/community/CommunityBoardServiceTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
package nova.mjs.community;

import nova.mjs.comment.repository.CommentRepository;
import nova.mjs.community.DTO.CommunityBoardRequest;
import nova.mjs.community.DTO.CommunityBoardResponse;
import nova.mjs.community.entity.CommunityBoard;
import nova.mjs.community.entity.enumList.CommunityCategory;
import nova.mjs.community.exception.CommunityNotFoundException;
import nova.mjs.community.likes.repository.CommunityLikeRepository;
import nova.mjs.community.repository.CommunityBoardRepository;
import nova.mjs.community.service.CommunityBoardService;
import nova.mjs.member.Member;
import nova.mjs.member.MemberRepository;
import nova.mjs.member.exception.MemberNotFoundException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.*;
import org.springframework.data.domain.*;

import java.util.*;

import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;

@ExtendWith(org.mockito.junit.jupiter.MockitoExtension.class)
class CommunityBoardServiceTest {

@InjectMocks
private CommunityBoardService communityBoardService;

@Mock
private CommunityBoardRepository communityBoardRepository;

@Mock
private CommunityLikeRepository communityLikeRepository;

@Mock
private MemberRepository memberRepository;

@Mock
private CommentRepository commentRepository;

private Member member;
private CommunityBoard board;

@BeforeEach
void setup() {
member = Member.builder()
.id(1L)
.email("test@example.com")
.name("Tester")
.build();

board = CommunityBoard.create(
"title", "content", CommunityCategory.FREE,
true, List.of("img1.jpg", "img2.jpg"), member
);
}

@Test
@DisplayName("게시글 목록 조회 - 로그인 사용자")
void testGetBoardsWithLogin() {
Pageable pageable = PageRequest.of(0, 10);
Page<CommunityBoard> boardPage = new PageImpl<>(List.of(board));

when(communityBoardRepository.findAll(pageable)).thenReturn(boardPage);
when(memberRepository.findByEmail("test@example.com")).thenReturn(Optional.of(member));
when(communityLikeRepository.countByCommunityBoardUuid(any())).thenReturn(5);
when(commentRepository.countByCommunityBoardUuid(any())).thenReturn(3);
when(communityLikeRepository.findCommunityUuidsLikedByMember(any(), anyList()))
.thenReturn(List.of(board.getUuid()));

Page<CommunityBoardResponse> result = communityBoardService.getBoards(pageable, "test@example.com");

assertThat(result).hasSize(1);
assertThat(result.getContent().get(0).isLiked()).isTrue();
}

@Test
@DisplayName("게시글 상세 조회 - 비로그인")
void testGetBoardDetailWithoutLogin() {
when(communityBoardRepository.findByUuid(board.getUuid())).thenReturn(Optional.of(board));
when(communityLikeRepository.countByCommunityBoardUuid(board.getUuid())).thenReturn(2);
when(commentRepository.countByCommunityBoardUuid(board.getUuid())).thenReturn(1);

CommunityBoardResponse response = communityBoardService.getBoardDetail(board.getUuid(), null);

assertThat(response.getTitle()).isEqualTo("title");
assertThat(response.isLiked()).isFalse();
}

@Test
@DisplayName("게시글 등록")
void testCreateBoard() {
CommunityBoardRequest request = CommunityBoardRequest.builder()
.title("New Post")
.content("Post content")
.published(true)
.contentImages(List.of("img1.png"))
.build();

when(memberRepository.findByEmail("test@example.com")).thenReturn(Optional.of(member));
when(communityBoardRepository.save(any())).thenReturn(board);
when(communityLikeRepository.countByCommunityBoardUuid(any())).thenReturn(0);
when(commentRepository.countByCommunityBoardUuid(any())).thenReturn(0);

CommunityBoardResponse response = communityBoardService.createBoard(request, "test@example.com");

assertThat(response.getTitle()).isEqualTo("New Post");
assertThat(response.getLikeCount()).isEqualTo(0);
}

@Test
@DisplayName("게시글 수정")
void testUpdateBoard() {
CommunityBoardRequest request = CommunityBoardRequest.builder()
.title("Updated Title")
.content("Updated Content")
.published(true)
.contentImages(List.of("imgX.jpg"))
.build();

when(communityBoardRepository.findByUuid(board.getUuid())).thenReturn(Optional.of(board));
when(communityLikeRepository.countByCommunityBoardUuid(any())).thenReturn(2);
when(commentRepository.countByCommunityBoardUuid(any())).thenReturn(1);
when(memberRepository.findByEmail("test@example.com")).thenReturn(Optional.of(member));
when(communityLikeRepository.findByMemberAndCommunityBoard(member, board)).thenReturn(Optional.empty());

CommunityBoardResponse response = communityBoardService.updateBoard(board.getUuid(), request, "test@example.com");

assertThat(response.getTitle()).isEqualTo("Updated Title");
assertThat(response.isLiked()).isFalse();
}

@Test
@DisplayName("게시글 삭제 - 작성자 본인")
void testDeleteBoard() {
// 작성자가 본인인 board 객체 생성
CommunityBoard authoredBoard = CommunityBoard.builder()
.title("title")
.content("content")
.published(true)
.category(CommunityCategory.FREE)
.contentImages(List.of("img1.jpg"))
.author(member) // 작성자 지정
.build();

when(communityBoardRepository.findByUuid(authoredBoard.getUuid())).thenReturn(Optional.of(authoredBoard));
when(memberRepository.findByEmail("test@example.com")).thenReturn(Optional.of(member));
doNothing().when(communityBoardRepository).delete(authoredBoard);

communityBoardService.deleteBoard(authoredBoard.getUuid(), "test@example.com");

verify(communityBoardRepository, times(1)).delete(authoredBoard);
}

@Test
@DisplayName("게시글 삭제 - 본인 아님")
void testDeleteBoardNotAuthor() {
Member another = Member.builder().email("other@example.com").build();

CommunityBoard authoredByAnother = CommunityBoard.builder()
.title("title")
.content("content")
.published(true)
.category(CommunityCategory.FREE)
.contentImages(List.of("img1.jpg"))
.author(another) // 다른 작성자
.build();

when(communityBoardRepository.findByUuid(authoredByAnother.getUuid())).thenReturn(Optional.of(authoredByAnother));
when(memberRepository.findByEmail("test@example.com")).thenReturn(Optional.of(member));

assertThatThrownBy(() ->
communityBoardService.deleteBoard(authoredByAnother.getUuid(), "test@example.com"))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("본인이 작성한 게시글만 삭제할 수 있습니다.");
}


@Test
@DisplayName("게시글 상세 조회 - 존재하지 않는 게시글")
void testGetBoardDetailNotFound() {
UUID fakeId = UUID.randomUUID();
when(communityBoardRepository.findByUuid(fakeId)).thenReturn(Optional.empty());

assertThatThrownBy(() -> communityBoardService.getBoardDetail(fakeId, null))
.isInstanceOf(CommunityNotFoundException.class);
}

@Test
@DisplayName("게시글 작성 - 존재하지 않는 유저")
void testCreateBoardFailMemberNotFound() {
when(memberRepository.findByEmail("none@example.com")).thenReturn(Optional.empty());

CommunityBoardRequest request = CommunityBoardRequest.builder()
.title("fail")
.content("fail")
.published(false)
.contentImages(List.of())
.build();

assertThatThrownBy(() ->
communityBoardService.createBoard(request, "none@example.com"))
.isInstanceOf(MemberNotFoundException.class);
}
}

63 changes: 63 additions & 0 deletions src/test/java/nova/mjs/community/CommunityBoardTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package nova.mjs.community;

import nova.mjs.community.entity.CommunityBoard;
import nova.mjs.community.entity.enumList.CommunityCategory;
import nova.mjs.member.Member;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.*;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@DisplayName("CommunityBoard 엔티티 테스트")
class CommunityBoardTest {

@Test
@DisplayName("CommunityBoard 빌더 테스트")
void testCommunityBoardBuilder() {
UUID uuid = UUID.randomUUID();
Member member = Member.builder().nickname("작성자").build();

CommunityBoard board = CommunityBoard.builder()
.uuid(uuid)
.title("제목")
.content("내용")
.category(CommunityCategory.FREE)
.published(true)
.publishedAt(LocalDateTime.of(2025, 5, 18, 10, 0))
.viewCount(0)
.likeCount(0)
.author(member)
.contentImages(new ArrayList<>())
.build();

assertThat(board.getUuid()).isEqualTo(uuid);
assertThat(board.getTitle()).isEqualTo("제목");
assertThat(board.getContent()).isEqualTo("내용");
assertThat(board.getCategory()).isEqualTo(CommunityCategory.FREE);
assertThat(board.getPublished()).isTrue();
assertThat(board.getPublishedAt()).isEqualTo(LocalDateTime.of(2025, 5, 18, 10, 0));
assertThat(board.getViewCount()).isZero();
assertThat(board.getLikeCount()).isZero();
assertThat(board.getAuthor().getNickname()).isEqualTo("작성자");
assertThat(board.getContentImages()).isEmpty();
}

@Test
@DisplayName("CommunityBoard 업데이트 메서드 테스트")
void testUpdate() {
Member member = Member.builder().nickname("작성자").build();

CommunityBoard board = CommunityBoard.create("초기제목", "초기내용", CommunityCategory.FREE, false, List.of("a.png"), member);
board.update("수정된 제목", "수정된 내용", true, List.of("b.png", "c.png"));

assertThat(board.getTitle()).isEqualTo("수정된 제목");
assertThat(board.getContent()).isEqualTo("수정된 내용");
assertThat(board.getPublished()).isTrue();
assertThat(board.getContentImages()).containsExactly("b.png", "c.png");
assertThat(board.getPublishedAt()).isNotNull(); // true로 바뀌었으므로 timestamp 갱신됨
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package nova.mjs.community.DTO;

import nova.mjs.community.entity.CommunityBoard;
import nova.mjs.member.Member;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

import static org.assertj.core.api.Assertions.assertThat;

class CommunityBoardResponseTest {

@Test
@DisplayName("CommunityBoard 엔티티를 DTO로 변환 - fromEntity 테스트")
void testFromEntity() {
// given
UUID uuid = UUID.randomUUID();
Member author = Member.builder()
.nickname("작성자닉네임")
.build();

CommunityBoard board = CommunityBoard.builder()
.uuid(uuid)
.title("테스트 제목")
.content("본문 내용")
.contentImages(List.of("img1.png", "img2.png"))
.viewCount(123)
.published(true)
.publishedAt(LocalDateTime.of(2025, 5, 18, 10, 0))
.author(author)
.build();

ReflectionTestUtils.setField(board, "createdAt", LocalDateTime.of(2025, 5, 18, 9, 0));
ReflectionTestUtils.setField(board, "updatedAt", LocalDateTime.of(2025, 5, 18, 9, 30));

int likeCount = 10;
int commentCount = 5;
boolean isLiked = true;

// when
CommunityBoardResponse response = CommunityBoardResponse.fromEntity(board, likeCount, commentCount, isLiked);

// then
assertThat(response.getUuid()).isEqualTo(uuid);
assertThat(response.getTitle()).isEqualTo("테스트 제목");
assertThat(response.getContent()).isEqualTo("본문 내용");
assertThat(response.getContentImages()).containsExactly("img1.png", "img2.png");
assertThat(response.getViewCount()).isEqualTo(123);
assertThat(response.getPublished()).isTrue();
assertThat(response.getPublishedAt()).isEqualTo(LocalDateTime.of(2025, 5, 18, 10, 0));
assertThat(response.getCreatedAt()).isEqualTo(LocalDateTime.of(2025, 5, 18, 9, 0));
assertThat(response.getUpdatedAt()).isEqualTo(LocalDateTime.of(2025, 5, 18, 9, 30));
assertThat(response.getLikeCount()).isEqualTo(10);
assertThat(response.getCommentCount()).isEqualTo(5);
assertThat(response.isLiked()).isTrue();
assertThat(response.getAuthor()).isEqualTo("작성자닉네임");
}
}
Loading