본문 바로가기

WINK-(Web & App)/Spring Boot 스터디

[2024 Spring Boot 스터디] 김호 #2 주차 - 본격적인 Spring Boot 3 Server 및 Test 환경 구성 (3 ~ 4장)

반응형

1. Spring Boot 3 개발 환경 개선

 본격적으로 Spring Boot 3 server를 구성하기 전에 개발 환경을 수정한다.

 

1-1. build.gradle 수정

[그림 1-1]

build.gradle의 기존 내용에 [그림 1-1]의 내용을 추가한다.

Spring Data JPA library는 Spring Boot 전용 JPA library이다.

H2 library는 local 및 test 환경에서 In-Memory Database의 data를 객체화하여 작업을 수행할 수 있는 환경을 지원한다.

Lombok library는 반복되는 method 작성 작업을 최소화하는 절차를 제공한다.

 

1-2. templates directory 생성

[그림 1-2]

HTML과 같은 view를 저장하기 위해 main/resources/ 경로에 templates directory를 생성한다.

 

1-3. application.yml 생성 

[그림 1-3]

 Spring Boot 관련 설정을 처리하는 application.yml을 main/resources/ 경로에 application.yml을 생성한다. Spring Boot server 실행 시 본 file이 자동으로 load된다.

 


2. Spring Boot 3의 핵심 구조

 Spring Boot 3는 Presentation, Business, 그리고 Persistent layer로 나뉘어져 있다. 각 계층은 독립적으로 기능을 수행하며 서로 query를 주고 받으며 타 계층에 영향을 미치지 않는다.

 

2-1. Presentation Layer

 Presentatoin Layer는 수신한 HTTP 요청을 Business layer로 전송한다. Controller가 본 역할을 수행하며, 여러 개가 존재할 수 있다.

[그림 2-1]

 main/java/[package]/ 경로의 TestController.java의 기존 내용을 삭제하고 [그림 2-1]의 내용을 작성한다. TestService instance는 Bean으로써 선언되었다. 

 

2-2. Business Layer

 Business layer는 data에 대해 이루어지는 처리 과정이 정의된 business logic 수행을 담당한다. Service가 본 역할을 수행한다.

[그림 2-2]

 main/java/[package]/ 경로에 TestService.java를 생성 후 [그림 2-2]의 내용을 작성한다. MeberRepository instance는 Bean으로써 선언되었다. List의 findAll() method는 List 내의 모든 element를 반환한다.

 

2-3. Persistent Layer

 Persistent layer는 database 관련 logic을 처리한다. 이 과정에서 database와 상호작용하는 DAO 객체를 사용할 수 있다. Repositery가 본 역할을 수행한다.

[그림 2-3]

 main/java/[package]/ 경로에 Member.java를 생성 후 [그림 2-3]의 내용을 작성한다. 

 

2-4. Mapping Interface

[그림 2-4]

member Table과 Member class를 mapping하기 위한 interface를 정의하기 위해, main/java/[package]/ 경로에 MemberRepository.java를 생성 후 [그림 2-4]의 내용을 작성한다. 

 

 

3. Run to Test

 [2]에서 구현한 layer class들이 정상적으로 작동하는지 test한다.

3-1. data.sql 생성

[그림 3-1]
[그림 3-2]

 main/resources/ 경로에 data.sql을 생성 후 [그림 3-2]의 내용을 작성한다.

Application 종료 시 이전에 수동적으로 입력된 data가 사라지는 In-Memory database의 휘발성으로 인한 문제점이 있다. 이때 미리 정의한 data.sql을 통해 applicatoin 실행 시 자동으로 data가 입력된다.

 

3-2. application.yml 작성

[그림 3-3]

 [1-3]에서 생성한 main/resources/application.yml에 [그림 3-3]의 내용을 작성한다.

show-sql 및 format_sql 구문은 application 실행 과정 중 database에 query 요청 시 모든 실행 구문을 표시한다.

defer-datasource-initialization 구문은  application 실행 시 table 생성 및 data.sql의 query를 실행한다.

 

3-3. Postman으로 HTTP 요청

[그림 3-4]

 Application 실행 후 Postman으로 "http://localhost:8080/test" 내용의 HTTP 요청을 전송한다.


4. Test Code

 Test code는 작성된 code가 정상적으로 작동하는지 확인할 목적으로 수행된다. 본 기능을 통해 기존 code를 수정할 필요가 없으며 유지보수에 좋다.

4-1. Given-When-Then Pattern

Test Code를 구성하는 방식 중 Given-When-Then Pattern을 채택하여 code를 작성한다.

Given은 test 실행을 준비하는 단계, When은 test를 진행하는 단계, 그리고 Then은 test 결과를 검증하는 단계이다.

 

4-2. JUnit

 JUnit은 Java의 Unit Test Framework이다. Unit Test는 code가 의도대로 작동하는지 unit으로써 검증하는 과정이며, unit은 보통 method이다.

 Junit의 이점으로 test 방식을 구분할 수 있는 Annotation을 제공하며, 사용 방법이 간편하다. 또한 자동으로 실행되는 결과에 대해 즉각적인 feedback을 제공한다.

 

4-2-1. JUnit Test Code 작성

[그림 4-1]
[그림 4-2]

 src/test/java/ 경로에 JUnitTest.java를 생성 후 [그림 4-2]의 내용을 작성한다. @Test Annotation을 method 위에 선언하므로써  해당 method가 Test Unit임을 정의한다.

 

[그림 4-3-1]
[그림 4-3-2]

  JUnitTest.java 실행 시 console에 [그림 4-3-1]의 결과가 표시된다. 만약 [그림 4-2]에서 int로 선언된 변수 b에 3을 할당 후 재실행하면, [그림 4-3-2]의 결과가 x 표시와 함께 도출된다.

 

 또한 JUnit은 test case가 하나 이상 실패하면 전체 test case가 실패한 것으로 간주한다.

 

4-2-2. 더 많은 Annotation

[그림 4-4]

 

src/test/java/ 경로에 JUnitCycleTest.java를 생성 후 [그림 4-4]의 내용을 작성한다. 각 Annotatoin은 다음 의미를 가진다:

 

1. @BeforeAll: 전체 test case 수행 전 처음 한 번만 실행 / 실행 주기에서 한 번만 호출되므로 static으로 선언

2. @BeforeEach: 각 test case 수행 전에 실행

3. @AfterAll: 전체 test case 종료 전 한 번만 실행 / 실행 주기에서 한 번만 호출되므로 static으로 선언

4. @AfterEach: 각 test case 종료 전 실행

 

[그림 4-5]

 JunitCycleTest.java 실행 시 [그림 4-5]의 결과가 출력된다.

 

4-3. AssertJ

AssertJ는 JUnit과 함께 사용하여 검증문의 가독성을 높이는 library이다. 

[그림 4-6-1]
[그림 4-6-2]

 [그림 4-6-1]의 기존 JUnit의 method에서 기댓값과 비굣값을 구분하기 어려우나, [그림 4-6-2]의 AssertJ의 method에서 기댓값과 비굣값을 구분하기 비교적 쉽다. AssertJ에 이와 같은 가독성 높은 method가 여러 존재한다.

 

4-4. TestController.java Test하기

[그림 4-7-1]

 

 TestController.java 내 class명에 cursor를 위치 후 표시되는 창에서, [More Action]을 선택하면 [그림 4-7-1]의 창이 표시된다.

 

[그림 4-7-2]

 

[Create Test] 선택 시 [그림 4-7-2] 창이 표시되며 제목이 자동으로 생성된다.

[그림 4-7-3]

[OK] 선택 후 src/test/java/[package]/ 경로를 선택하여 Test file을 생성한다. 

 

[그림 4-8]

TestControllerTest.java에 [그림 4-8]의 내용을 작성한다. 

 

 @SpringBootTest Annotation은 @SpringBootApplication Annotation이 존재하는 class 내 Bean을 탐색 후 test용 Application  Context를 생성한다.

 @AutoConfigureMockMvc Annotation은 MockMvc를 생성하고 자동 구성을 수행한다. MockMvc는 application을 server에 배포하지 않고도 test용 MVC 환경을 만들어 요청 및 전송, 그리고 응답 기능을 제공하는 Utility Class이다. Controller Test 시 사용된다.

 

[그림 4-9]

 Class의 기본 생성자와 Getter 및 Setter를 자동으로 정의하는 Lombok Plugin을 설치한다.

 

 

[그림 4-10]

 본 class 내에 [그림 4-10]의 내용을 추가한다.

 

1. perform() method는 요청을 전송하여 결과로 ResultActions 객체를 받는데, 이때 해당 객체는 andExpect() method로 반환값을 검증한다.

2. andExpect() method는 응답을 검증한다. 본 code에서 isOk() method를 사용하여 status 200 응답을 검증한다.

3. accept() method는 요청 시 어떤 type으로 응답을 받을지 정의하는 method이다. 본 코드에서 JSON을 정의했다.

4. jsonPath("$[i].${field}")은 JSON 응답 내 i번 째 field 값을 가져온다.

 

[그림 4-11]

 본 java 실행 시 test 결과가 성공적으로 수행되었음을 확인한다.

반응형