코드 그라데이션
230217 Service단 TestCode 전후 비교 본문
전체 코드(한꺼번에 연달아서 붙여넣기)
컨트롤러
@RestController
@RequestMapping("/boards")
@RequiredArgsConstructor
public class BoardController {
private final BoardService boardService;
private final SetHttpHeaders httpHeaders;
// 게시글 생성
@PostMapping
public ResponseEntity<StatusResponse> createBoard(
@RequestBody BoardRequestDto boardRequestDto,
@AuthenticationPrincipal UserDetailsImpl userDetails) {
boardService.createBoard(boardRequestDto, userDetails.getUser());
return ResponseEntity.status(HttpStatus.CREATED)
.body(StatusResponse.valueOf(ResponseMessages.CREATED_SUCCESS));
}
// 게시글 수정
@PutMapping("/{boardId}")
public ResponseEntity<StatusResponse> updateBoard(@PathVariable Long boardId,
@RequestBody BoardRequestDto boardRequestDto,
@AuthenticationPrincipal UserDetailsImpl userDetails) {
boardService.updateBoard(boardId, boardRequestDto, userDetails.getUser());
return ResponseEntity.ok().body(StatusResponse.valueOf(ResponseMessages.SUCCESS));
}
// 게시글 단건 조회, 댓글 목록으로 불러오게 추가(페이징)
@GetMapping("/{boardId}")
public ResponseEntity<BoardResponseDto> getBoard(@PathVariable Long boardId) {
return ResponseEntity.ok().headers(httpHeaders.setHeaderTypeJson())
.body(boardService.getBoard(boardId));
}
// 게시글 전체 조회
@GetMapping
public ResponseEntity<Page<PagingBoardResponse>> getBoards(@RequestBody PageDto pageDto) {
return ResponseEntity.ok().headers(httpHeaders.setHeaderTypeJson()).body(boardService.getBoards(pageDto));
}
// 게시물 삭제
@DeleteMapping("{boardId}")
public ResponseEntity<StatusResponse> deleteBoard(@PathVariable Long boardId,
@AuthenticationPrincipal UserDetailsImpl userDetails) {
boardService.deleteBoard(boardId, userDetails.getUser());
return ResponseEntity.status(HttpStatus.NO_CONTENT).body(StatusResponse.valueOf(ResponseMessages.DELETE_SUCCESS));
}
}
RequestDto
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class BoardRequestDto {
private String title;
private String content;
private BoardSubject subject;
}
ResponseDto
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class BoardResponseDto {
private String title;
private String content;
private BoardSubject subject;
private List<CommentResponseDto> comments;
private LocalDateTime createdAt;
private LocalDateTime modifiedAt;
}
PagingBoardResponseDto
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class PagingBoardResponse {
private String title;
private BoardSubject subject;
public PagingBoardResponse(Board board) {
this.title = board.getTitle();
this.subject = board.getSubject();
}
}
Board
@Entity
@Getter
@NoArgsConstructor
public class Board extends TimeStamped {
/**
* 컬럼 - 연관관계 컬럼을 제외한 컬럼을 정의합니다.
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String content;
@Enumerated(EnumType.STRING)
private BoardSubject subject;
public enum BoardSubject {
공지사항, 동네소식;
}
/**
* 생성자 - 약속된 형태로만 생성가능하도록 합니다.
*/
@Builder
public Board(String title, String content, BoardSubject subject, User user) {
this.title = title;
this.content = content;
this.subject = subject;
this.user = user;
}
/**
* 연관관계 - Foreign Key 값을 따로 컬럼으로 정의하지 않고 연관 관계로 정의합니다.
*/
@ManyToOne(fetch = FetchType.LAZY)
private User user;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true,fetch = FetchType.EAGER)
private Set<Comment> comments = new LinkedHashSet<>();
/**
* 연관관계 편의 메소드 - 반대쪽에는 연관관계 편의 메소드가 없도록 주의합니다.
*/
/**
* 서비스 메소드 - 외부에서 엔티티를 수정할 메소드를 정의합니다. (단일 책임을 가지도록 주의합니다.)
*/
public void update(BoardRequestDto boardRequestDto) {
this.title = boardRequestDto.getTitle();
this.content = boardRequestDto.getContent();
this.subject = boardRequestDto.getSubject();
}
public boolean checkBoardWriter(User user) {
return this.user.equals(user); // board가 가지고 있는 유저와 파라미터로 받은 유저를 비교해서 true false반환
}
}
BoardRepository
@Repository
public interface BoardRepository extends JpaRepository<Board, Long> {
Page<Board> findAll(Pageable pageable);
}
BoardService(Interface)
public interface BoardService {
Board createBoard(BoardRequestDto boardRequestDto, User user);
void updateBoard(Long boardId, BoardRequestDto boardRequestDto, User user);
BoardResponseDto getBoard(Long boardId);
Page<PagingBoardResponse> getBoards(PageDto pageDto);
void deleteBoard(Long boardId, User user);
Board findBoardById(Long boardsId);
}
BoardServiceImpl
@Service
@RequiredArgsConstructor
public class BoardServiceImpl implements BoardService {
private final BoardRepository boardRepository;
// 게시글 생성
@Override
@Transactional
public Board createBoard(BoardRequestDto boardRequestDto, User user) {
Board board = Board.builder()
.title(boardRequestDto.getTitle())
.content(boardRequestDto.getContent())
.subject(boardRequestDto.getSubject())
.user(user)
.build();
return boardRepository.save(board);
}
// 게시글 수정
@Override
@Transactional
public void updateBoard(Long boardId, BoardRequestDto boardRequestDto, User user) {
Board board = findBoardById(boardId);
if (!board.checkBoardWriter(user)) {
throw new IllegalArgumentException("본인 게시글이 아닙니다");
}
board.update(boardRequestDto);
}
// 게시글 전체 조회
@Override
@Transactional(readOnly = true)
public Page<PagingBoardResponse> getBoards(PageDto pageDto) {
Page<Board> boards = boardRepository.findAll(pageDto.toPageable());
return boards.map(PagingBoardResponse::new);
}
// 게시글 단건 조회
@Override
@Transactional(readOnly = true)
public BoardResponseDto getBoard(Long boardId) {
Board board = findBoardById(boardId);
return BoardResponseDto.builder()
.title(board.getTitle())
.content(board.getContent())
.subject(board.getSubject())
.comments(board.getComments().stream().map(CommentResponseDto::new).collect(Collectors.toList()))
.createdAt(board.getCreatedAt())
.modifiedAt(board.getModifiedAt())
.build();
}
// 게시글 삭제
@Override
@Transactional
public void deleteBoard(Long boardId, User user) {
Board board = findBoardById(boardId);
if(!board.checkBoardWriter(user)) {
throw new IllegalArgumentException("본인의 게시글이 아닙니다.");
}
boardRepository.deleteById(board.getId());
}
// 중복 로직 메서드 분리
@Override
@Transactional(readOnly = true)
public Board findBoardById(Long boardId) {
return boardRepository.findById(boardId).orElseThrow(() -> new IllegalArgumentException("게시글이 없습니다."));
}
}
-----------------------------------------------------------------------------------------
작성한 테스트 코드 초안
@ExtendWith(MockitoExtension.class)
class BoardServiceImplTest {
@Mock
BoardRepository boardRepository;
@InjectMocks
BoardServiceImpl boardService;
@Test
@DisplayName("게시글 생성 성공 테스트")
void createBoard() {
BoardRequestDto requestDto = BoardRequestDto.builder()
.title("title1")
.content("content1")
.build();
User user = mock(User.class);
//when
boardService.createBoard(requestDto, user);
//then
verify(boardRepository).save(isA(Board.class));
}
@Test
@DisplayName("게시글 업데이트 성공 테스트")
void updateBoard() {
// given
User user = mock(User.class);
Board board = mock(Board.class);
BoardRequestDto boardRequestDto = mock(BoardRequestDto.class);
when(boardRepository.findById(board.getId())).thenReturn(Optional.of(board));
when(Optional.of(board).get().checkBoardWriter(user)).thenReturn(true);
// when
boardService.updateBoard(board.getId(), boardRequestDto, user);
// then
verify(board).update(boardRequestDto);
}
@Test
@DisplayName("게시글 목록 불러오기 테스트")
void getBoards() {
// given
Pageable pageable = mock(Pageable.class);
PageDto pageDto = mock(PageDto.class);
when(pageDto.toPageable()).thenReturn(pageable);
when(boardRepository.findAll(pageable)).thenReturn(Page.empty());
// when
Page<PagingBoardResponse> pagingProductResponse = boardService.getBoards(pageDto);
// then
assertThat(pagingProductResponse).isNotNull();
}
@Test
@DisplayName("게시글 단건 조회 테스트")
void getBoard() {
// given
BoardRequestDto boardRequest = mock(BoardRequestDto.class);
Board board = mock(Board.class);
when(boardRepository.findById(board.getId())).thenReturn(Optional.of(board));
// when
BoardResponseDto boardResponse = boardService.getBoard(board.getId());
// then
assertThat(boardResponse.getContent()).isEqualTo(boardRequest.getContent());
}
@Test
@DisplayName("게시글 삭제 성공 테스트")
void deleteBoard() {
//given
Board board = mock(Board.class);
User user = mock(User.class);
when(boardRepository.findById(board.getId())).thenReturn(Optional.of(board));
when(Optional.of(board).get().checkBoardWriter(user)).thenReturn(true);
//when
boardService.deleteBoard(board.getId(),user);
//then
verify(boardRepository).deleteById(board.getId());
}
}
수정 후
@ExtendWith(MockitoExtension.class)
class BoardServiceImplTest {
@Mock
BoardRepository boardRepository;
@InjectMocks
BoardServiceImpl boardService;
@Test
@DisplayName("게시글 생성 성공 테스트")
void createBoard() {
BoardRequestDto requestDto = BoardRequestDto.builder()
.title("title1")
.content("content1")
.subject(Board.BoardSubject.공지사항)
.build();
User user = mock(User.class);
Board board = Board.builder()
.title(requestDto.getTitle())
.content(requestDto.getContent())
.subject(Board.BoardSubject.공지사항)
.build();
given(boardRepository.save(any())).willReturn(board);
//when
Board savedBoard = boardService.createBoard(requestDto, user);
// then
assertThat(savedBoard.getTitle()).isEqualTo(requestDto.getTitle());
assertThat(savedBoard.getContent()).isEqualTo(requestDto.getContent());
}
@Test
@DisplayName("게시글 업데이트 성공 테스트")
void updateBoard() {
// given
User user = mock(User.class);
Board board = Board.builder()
.title("test-title")
.content("test-content")
.subject(Board.BoardSubject.동네소식)
.user(user)
.build();
BoardRequestDto boardRequestDto = BoardRequestDto.builder()
.title("after-title")
.content("after-content")
.subject(Board.BoardSubject.공지사항)
.build();
when(boardRepository.findById(board.getId())).thenReturn(Optional.of(board));
// when
boardService.updateBoard(board.getId(), boardRequestDto, user);
// then
assertThat(board.getTitle()).isEqualTo(boardRequestDto.getTitle());
assertThat(board.getContent()).isEqualTo(boardRequestDto.getContent());
assertThat(board.getSubject()).isEqualTo(boardRequestDto.getSubject());
}
@Test
@DisplayName("게시글 업데이트 실패 테스트: 본인 게시글이 아닌 경우")
void failsUpdateBoard() {
// given
User userA = User.builder()
.username("userA")
.password("password1")
.build();
User userB = User.builder()
.username("userB")
.password("password2")
.build();
Board board = Board.builder()
.title("test-title")
.content("test-content")
.subject(Board.BoardSubject.동네소식)
.user(userA)
.build();
when(boardRepository.findById(board.getId())).thenReturn(Optional.of(board));
// when
assertThatThrownBy(() -> {
boardService.updateBoard(board.getId(), null, userB);
}).isInstanceOf(IllegalArgumentException.class);
}
@Test
@DisplayName("게시글 목록 불러오기 테스트")
void getBoards() {
// given
Pageable pageable = mock(Pageable.class);
PageDto pageDto = mock(PageDto.class);
when(pageDto.toPageable()).thenReturn(pageable);
when(boardRepository.findAll(pageable)).thenReturn(Page.empty());
// when
Page<PagingBoardResponse> pagingProductResponse = boardService.getBoards(pageDto);
// then
assertThat(pagingProductResponse).isNotNull();
}
@Test
@DisplayName("게시글 단건 조회 테스트")
void getBoard() {
// given
Board board = Board.builder()
.title("test-title")
.content("test-content")
.build();
when(boardRepository.findById(board.getId())).thenReturn(Optional.of(board));
// when
BoardResponseDto boardResponse = boardService.getBoard(board.getId());
// then
assertThat(boardResponse.getContent()).isEqualTo(board.getContent());
assertThat(boardResponse.getTitle()).isEqualTo(board.getTitle());
}
@Test
@DisplayName("게시글 삭제 성공 테스트")
void deleteBoard() {
//given
Board board = mock(Board.class);
User user = mock(User.class);
when(boardRepository.findById(board.getId())).thenReturn(Optional.of(board));
when(Optional.of(board).get().checkBoardWriter(user)).thenReturn(true);
//when
boardService.deleteBoard(board.getId(),user);
//then
verify(boardRepository, times(1)).deleteById(board.getId());
}
}
728x90
'Spring > Test Code' 카테고리의 다른 글
230217 BoardServiceImpl 테스트 코드 (2) 게시글 수정 성공 / 실패 (0) | 2023.02.26 |
---|---|
230217 BoardServiceImpl 테스트 코드 (1) 게시글 생성 - 비교 (0) | 2023.02.26 |
20230210 테스트 코드 추가 설명 (4) 프로필 정보 조회 실패 테스트 (0) | 2023.02.16 |
20230210 테스트 코드 추가 설명 (3) 프로필 정보 조회 성공 테스트 (0) | 2023.02.16 |
20230210 테스트 코드 추가 설명 (2) 회원 정보 업데이트 실패 테스트 (0) | 2023.02.15 |
Comments