본문 바로가기
Programming/Spring Boot

[실습] 스프링부트(Spring Boot)로 공지사항/게시판 구현하기 - DB Table, Entity, Repository 구현 및 CRUD 테스트 구현하기

by 돌방로그 2023. 1. 27.

제목의 글을 설명하기에 앞서 정보전달의 목적도 있지만,
제가 잊지않기 위해서 공부 및 정리하며 쓰는 글이라는 사실을 미리 고지합니다.

혹시라도 오입력된 정보가 있다면, 댓글 남겨주세요!


오늘의 Spring Boot 실습 목표는 "공지사항/게시판 만들어보기!" 입니다.
본 게시글에서 다루는 사항은 공지사항/게시판의 기능을 구현하기 위해 DB(Table)을 생성 및 해당 테이블에 대한 CRUD를 테스트 코드를 작성하는 과정입니다.


공지사항/게시판 구현하기 - DB Table 생성 및 CRUD 테스트

사전 준비

아래 사항에 대해서 사전 준비가 완료되지 않으신 분들은 아래 링크를 참조하여 사전 준비를 진행합니다.

 

혹시라도 아래 개념이 잘 기억나지 않으시는 분들은 관련 링크를 참조하시기 바랍니다.

 

 

파일 구조

Notice User 테이블을 생성하고 CRUD 기능을 테스트하기 위해서 작업해야 할 파일은 총 3개입니다.

아래 폴더/파일 트리 구조와 호출 흐름도는 Notice User 테이블이 전체 구현이 완료된 후 갖춰질 구조입니다.

작업할 파일에 대한 간략한 설명은 아래를 참고하시면 됩니다.

  • NoticeUser
    • 목적: Notice User 테이블과 매핑되는 객체 정의 파일
    • 경로: src\main\java\...\notice\domain
  • NoticeUserRepository
    • 목적: NoticeUser에 대한 메소드 정의 파일
    • 경로: src\main\java\...\notice\repository
  • NoticeUserRepositoryTest
    • 목적: Notice User 테이블에 관련된 CRUD를 테스트 코드가 구현된 파일
    • 경로: src\test\java\...\notice\domain

 

 

테이블 구조

[실습] 스프링부트(Spring Boot)로 공지사항/게시판 구현하기 - DB, API 기획/설계하기 를 참조해주세요.

 

 

결과 이미지

 

 

소스 코드

NoticeUser

위 '테이블 구조'에 링크된 페이지에서 정의한 바와 같이 각 컬럼의 타입과 길이, 속성을 지정합니다.

package com.logsjejustone.webapiserver.notice.domain;

import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.data.annotation.CreatedDate;

import java.time.LocalDateTime;

@Getter
@Setter
@NoArgsConstructor
@Entity
public class NoticeUser {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer Id;

    @Column(length = 6)
    @NotNull
    private String registerEmployeeNo;
    
    @CreatedDate
    @NotNull
    private LocalDateTime registerDatetime;

    @Column(length = 6)
    @NotNull
    private String updateEmployeeNo;
    
    @CreatedDate
    @NotNull
    private LocalDateTime updateDatetime;

    @Column(length = 20)
    private String category;

    @Column(length = 200)
    private String title;
    
    @Column(columnDefinition = "TEXT")
    private String content;
}

 

NoticeUserRepository

NoticeUser 테이블에 대한 메소드를 정의하는 부분으로 JpaRepository를 상속받아 기본적인 메소드들은 별도로 정의하지 않고 이용할 수 있습니다. 

기본적으로 사용할 수 있는 메소드는 'JpaRepository' 링크를 참조해주세요.

package com.logsjejustone.webapiserver.notice.repository;

import com.logsjejustone.webapiserver.notice.domain.NoticeUser;
import org.springframework.data.jpa.repository.JpaRepository;

public interface NoticeUserRepository extends JpaRepository<NoticeUser, Integer> {

}

 

NoticeUserRepositoryTest

NoticeUserRepository를 이용하여 NoticeUser로 매핑된 테이블 객체에 대해서 기본적인 CRUD를 테스트하는 코드입니다.

자세한 코드는 아래 더보기를 클릭하여 확인해주시고, 상세한 코드는 아래 '테스트' 카테고리에서 코드와 결과를 상세하게 기록하겠습니다

더보기
package com.logsjejustone.webapiserver.notice.repository;

import com.logsjejustone.webapiserver.notice.domain.NoticeUser;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.Optional;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class NoticeUserRepositoryTest {
    @Autowired
    private NoticeUserRepository noticeUserRepository;

    @Test
    public void createNotice () {
        // Check 1
        LocalDateTime now = LocalDateTime.now();
        String employeeNo = "000000";

        NoticeUser noticeUser = new NoticeUser();
        noticeUser.setRegisterDatetime(now);
        noticeUser.setRegisterEmployeeNo(employeeNo);
        noticeUser.setUpdateDatetime(now);
        noticeUser.setUpdateEmployeeNo(employeeNo);

        noticeUser.setCategory("시스템 점검");
        noticeUser.setTitle("2022/11/30 시스템 점검 공지");
        noticeUser.setContent("아래와 같은 일정으로 시스템 점검 예정임.");

        this.noticeUserRepository.save(noticeUser);
        assertEquals(1, this.noticeUserRepository.count());
    }

    @Test
    public void readNotice () throws Exception {
        // Check 1
        List<NoticeUser> lstNoticeUser = this.noticeUserRepository.findAll();
        assertEquals(0, lstNoticeUser.size());
    }

    @Test
    public void updateNotice () throws Exception {
        // Check 1
        Optional<NoticeUser> optNotice = this.noticeUserRepository.findById(2);
        assertTrue(optNotice.isPresent());

        // Check 2
        NoticeUser noticeUser = optNotice.get();
        assertEquals("2022/11/30 시스템 점검 공지", noticeUser.getTitle());

        // Check 3
        String strAfter = "2022/12/30 시스템 점검 공지";
        noticeUser.setTitle(strAfter);
        this.noticeUserRepository.save(noticeUser);
        assertEquals(strAfter, optNotice.get().getTitle());
    }

    @Test
    public void deleteNotice () throws Exception {
        // Check 1
        Optional<NoticeUser> optNotice = this.noticeUserRepository.findById(2);
        assertTrue(optNotice.isPresent());

        // Check 2
        NoticeUser noticeUser = optNotice.get();
        assertEquals("2022/12/30 시스템 점검 공지", noticeUser.getTitle());

        // Check 3
        this.noticeUserRepository.delete(noticeUser);
        assertEquals(0, this.noticeUserRepository.count());
    }
}

 

 

테스트

CREATE

결과 #1: 테스트 코드 한 번 수행

  • 좌측 이미지: JUnit 자체적으로 assertEquals 메소드를 통해 확인한 테스트 결과 → Success (예상값과 실제값이 일치)
  • 우측 이미지: MySQL Workbench에서 생성된 notice_user 테이블과 1개의 데이터가 확인됨

 

결과 #2: 테스트 코드 두 번 수행 (결과 #1 이후 한 번 더 클릭한 경우)

  • 좌측 이미지: JUnit 자체적으로 assertEquals 메소드를 통해 확인한 테스트 결과 → Fail (예상값과 실제값이 불일치)
    • 의도적으로 Fail이 발생하도록 코드를 구현하였으며, 셋팅된 예상값은 1, 실제값은 2입니다.
  • 우측 이미지: MySQL Workbench에서 notice_user 테이블에 데이터 2개가 확인됨

 

코드

@Test
public void createNotice () {
    // Check 1
    LocalDateTime now = LocalDateTime.now();
    String employeeNo = "000000";

    NoticeUser noticeUser = new NoticeUser();
    noticeUser.setRegisterDatetime(now);
    noticeUser.setRegisterEmployeeNo(employeeNo);
    noticeUser.setUpdateDatetime(now);
    noticeUser.setUpdateEmployeeNo(employeeNo);

    noticeUser.setCategory("시스템 점검");
    noticeUser.setTitle("2022/11/30 시스템 점검 공지");
    noticeUser.setContent("아래와 같은 일정으로 시스템 점검 예정임.");

    this.noticeUserRepository.save(noticeUser);
    assertEquals(1, this.noticeUserRepository.count());
}

 

Query

해당 스키마/DB 내에는 notice_user 테이블이 없기 때문에 Hibernate 자체적으로 DDL Create 문을 생성하여 테이블을 생성 후, 입력한 데이터를 삽입합니다.

 

READ

결과

  • JUnit 자체적으로 assertEquals 메소드를 통해 확인한 테스트 결과 → Success (예상값과 실제값이 일치)

 

코드

@Test
public void readNotice () throws Exception {
    // Check 1
    List<NoticeUser> lstNoticeUser = this.noticeUserRepository.findAll();
    assertEquals(2, lstNoticeUser.size());
}

 

Query

 

UPDATE

결과

  • 좌측 이미지: JUnit 자체적으로 assertEquals 메소드를 통해 확인한 테스트 결과 → Success (예상값과 실제값이 일치)
  • 우측 이미지: id가 1번인 항목의 title의 날짜가 '2022/12/30'에서 '2022/11/30'으로 변경되었음

 

코드

@Test
public void updateNotice () throws Exception {
    // Check 1
    Optional<NoticeUser> optNotice = this.noticeUserRepository.findById(2);
    assertTrue(optNotice.isPresent());

    // Check 2
    NoticeUser noticeUser = optNotice.get();
    assertEquals("2022/11/30 시스템 점검 공지", noticeUser.getTitle());

    // Check 3
    String strAfter = "2022/12/30 시스템 점검 공지";
    noticeUser.setTitle(strAfter);
    this.noticeUserRepository.save(noticeUser);
    assertEquals(strAfter, optNotice.get().getTitle());
}

 

Query

 

DELETE

결과

  • 좌측 이미지: JUnit 자체적으로 assertEquals 메소드를 통해 확인한 테스트 결과 → Fail (예상값과 실제값이 불일치)
    • 의도적으로 Fail이 발생하도록 코드를 구현하였으며, 셋팅된 예상값은 0, 실제값은 1입니다.
  • 우측 이미지: id가 2번인 항목에 대해서 데이터가 삭제되었음

 

코드

@Test
public void deleteNotice () throws Exception {
    // Check 1
    Optional<NoticeUser> optNotice = this.noticeUserRepository.findById(2);
    assertTrue(optNotice.isPresent());

    // Check 2
    NoticeUser noticeUser = optNotice.get();
    assertEquals("2022/12/30 시스템 점검 공지", noticeUser.getTitle());

    // Check 3
    this.noticeUserRepository.delete(noticeUser);
    assertEquals(0, this.noticeUserRepository.count());
}

 

Query

 

 


댓글