반응형

 

↓↓↓ 이전 내용

2023.12.15 - [Web Application/Backend] - [REST API] Spring Boot로 REST API CRUD 간단 구현 (5)-사용자 정의 ResponseEntity

 

[REST API] Spring Boot로 REST API CRUD 간단 구현 (5)-사용자 정의 ResponseEntity

이전 내용↓↓↓ 2023.11.22 - [Web Application/Backend] - [REST API] Spring Boot로 REST API CRUD 간단 구현 (4)-예외처리/handle Exception [REST API] Spring Boot로 REST API CRUD 간단 구현 (4)-예외처리/handle Exception 이전 내용↓

im-gonna.tistory.com

💡 JUnit test 기본 설정

 

작성한 코드가 백에서 잘 동작하는 지를 확인하기 위해 TEST하는 기능이 있다.

스프링 부트에서는 JUnit을 활용하여 테스트 한다.

 

JUnit을 이용한 테스트 시 다음 네가지 종속성을 확인해야 한다.

JUNIT5, AssertJ, Mockito, H2Database

 

기본적으로 spring initializer로 프로젝트 생성 시 앞에 3개는 자동으로 종속되어 있다.

build.gradle의 dependency를 보면 확인이 가능하다.

 

따라서 h2 database만 따로 종속성을 추가해준다.

test시에 사용할 것이므로 다음 코드를 추가한다.

testImplementation 'com.h2database:h2:1.4.200'

 

test 사용 시 필요한 기능을 갖춘 종속성은 모두 추가해주었다.

 

그렇다면 test는 어디서 진행되는 것일까?

 

 

디렉토리를 보면 main과 test가 나란히 있는 것을 알 수 있다.

우리는 지금까지 main 이하에 디렉토리와 클래스를 생성해가며 실행했었지만, 나란히 존재하는 test 디렉토리에서는 unit test를 진행할 수 있다. 여기서 test를 실행한다.

 

실제 프로젝트가 돌아가는 동작은 main에서 일어난다. main에도 java와 resources 하위 디렉토리가 존재한다.

따라서 test를 위한 test 디렉토리 하에도 java와 병렬하게 resources 디렉토리를 생성해주자.

resources 디렉토리를 생성하였으면 그 안에 application.yml 파일을 추가해준다.

 

테스트 시 사용하는 데이터베이스는 h2이기 때문에, 스프링부트에 내장된 h2 데이터베이스를 연동하기 위해서 아래 코드를 yml파일에 추가해준다.

spring:
  datasource:
    url: jdbc:h2://mem:db;DB_CLOSE_DELAY=-1
    username: sa
    password: sa
    driver-class-name: org.h2.Driver

  # The SQL dialect makes Hibernate generate better SQL for the chosen database
  jpa:
    properties:
      hibernate:
        dialect: org.hibernate.dialect.H2Dialect
    show-sql: true

  #JPA settings
  jpa.hibernate.ddl-auto: create-drop

 

create-drop으로 하는 이유는 스프링부트를 종료했을 때 모두 drop하고 새로운 애플리케이션이 돌아갔을 때 새로 받기 위함이다.

 

💡 Repository test

 

이제 테스트를 할 기초 준비를 마쳤으니, repository의 동작부터 test해보자.

 

main의 형태와 동일하게 test에서도 repository 디렉토리를 만들어주고, 그 아래 CloudVendorRepositoryTest 클래스를 추가하여 CloudVendorRepository를 test한다.

 

 

이제 클래스를 test클래스로 정의해주자.

 

repository test 클래스를 test하기 위해서 @DataJpaTest 어노테이션을 추가해 식별해준다.

이때, 테스트 작업을 할 때, 모든 초기화 작업을 수행하는 것이 모범 사례이다.

무슨 의미이냐 하면, 테스트를 할 때도 비교할 만한 대상이 있어야 하기 때문에, 테스트 용 데이터를 넣어준다는 것이다.

 

main에서 만들어준 CloudVendorRepository가 정상 동작하는 지 확인해야 하기 때문에, repository를 하나와, 데이터를 저장해주기 위해 CloudVendor 객체를 하나 정의해 준다.

 

  • 설정 메서드

 

설정 메서드를 통해 각 test케이스가 실행되기 전에, 미리 데이터베이스에 테스트 용 객체를 생성해준다.

위와 같은 값을 가지는 CloudVendor 객체를 생성해주고, 데이터 베이스에 저장해준다.

 

  • 해제 메서드

 

해제 메서드를 통해 각 test케이스가 실행되고 난 후에는, 다시 객체를 반환하여 메모리를 반환해준다.

 

 

  • 성공 테스트

먼저, 성공적으로 조회가 된 경우에 대한 테스트를 정의해보자.

  • 테스트 케이스를 사용할 때마다 @Test 어노테이션을 사용하여, 아래 메서드가 일반 메서드가 아니라, 테스트 케이스임을 식별할 수 있다. 따라서 이 표시가 있는 메서드 옆에는 개별적으로 실행할 수 있도록 재생 표시가 있는 것을 확인할 수 있다.
  • 이 test의 메서드 이름은 testFindByVendorName_Found이다.
  • cloudVendorRepository의 findByVendorName을 통해 "Amazon"을 이름으로 가진 cloudVendor를 찾도록 하여 조회 결과를 list에 저장한다.
  • assertThat을 통해 실제로 예상되는 값을 반환하는지 확인할 수 있다.
  • asserThat을 통해 list에 저장된 cloudVendor의 id가, 우리가 설정해준 Amazon의 id와 동일한지 확인한다.
  • asserThat을 통해 list에 저장된 cloudVendor의 Address가, 우리가 설정해준 Amazon의 Address와 동일한지 확인한다.
  • 모두 동일하다면 이 테스트는 성공적인 결과를 반환할 것이다.

 

첫번째 테스트에 대한 실행 결과 로그를 살펴보자.

 

select와 insert 쿼리가 실행되며 데이터베이스에 입력하고, 주어진 입력에 대해 조회한 것을 확인할 수 있다.

 

또한 EmbeddedDatabaseFactory 사용을 시작하는 것과 함께, 스프링부트에 내장된 jdbc h2 데이터베이스를 사용한다는 것을 확인할 수 있다.

즉, 테스트 시에는 내 pc에 있는 mysql db가 아닌, 내장된 h2 데이터베이스를 사용하여 테스트 한다.

 

  • 실패 테스트

다음으로, 조회에 실패한 경우에 대한 테스트를 정의해보자.

 

 

  • 데이터베이스에 존재하지 않는 cloudvendor 이름을 찾으려고 하는 실패 테스트 케이스에 대한 테스트이다.
  • 현재는 내장 db에 Amazon 객체만 들어가 있는 상태임을 명심하자.
  • 이 메서드는 testFindByVendorName_NotFound이다.
  • 마찬가지로, repository 조회를 GCP로 조회하고 그 결과를 list에 저장하도록 한다.
  • 당연히 내장 db에는 Amazon에 대한 데이터밖에 없기 때문에 GCP로 조회한 결과는 비어있어야 한다.
  • 이를 확인하기 위해 asserThat 메서드를 통해서 lsit가 비어 있음이 true임을 확인하도록 한다.
  • 이 assertion이 통과하면 리스트는 비어있다는 것이고, 이 테스트는 성공적으로 통과하게 된다.

 

💡 respository test 클래스에 대한 실행 결과

 레포지토리 테스트 클래스를 실행한 결과, 내부에 있는 unit 테스트 두개(성공사례, 실패사례) 모두 성공적으로 잘 테스트 되었음을 ✔표시를 통해 확인할 수 있다.

 

만약 test case가 잘못 적용된다면 어떻게 될까? 다음과 같이 실패 케이스에서 isTrue 부분을 isFalse로 바꾸어 보자.

 

 

테스트 결과 NotFound 테스트에서는 실패 표시가 나타나고, 왜 실패했는지 옆에 로그를 통해 설명해주고 있다.

테스트 로직 내에서는 FALSE를 기대했으나, 실제 값은 TRUE를 반환하므로 테스트 결과가 실패로 뜨고 있다.

따라서 이런 로그를 통해 테스트 내에서 어떤 값을 예상하고 출력하는지 확인함으로써 수정할 수 있다.

 

이렇게 Repository test를 수행할 수 있다!

 

 

↓↓↓ 다음 내용

2024.01.05 - [Web Application/Backend] - [REST API] Spring Boot로 REST API CRUD 간단 구현 (7) - JUnit TEST service 계층 test 예제

 

[REST API] Spring Boot로 REST API CRUD 간단 구현 (7) - JUnit TEST service 계층 test 예제

↓↓↓ 이전 내용 2023.12.30 - [Web Application/Backend] - [REST API] Spring Boot로 REST API CRUD 간단 구현 (6) - JUnit TEST 기본 설정 및 repository 계층 test 예제 [REST API] Spring Boot로 REST API CRUD 간단 구현 (6) - JUnit TEST

im-gonna.tistory.com

 

반응형
반응형

이전 내용↓↓↓

2023.11.22 - [Web Application/Backend] - [REST API] Spring Boot로 REST API CRUD 간단 구현 (4)-예외처리/handle Exception

 

[REST API] Spring Boot로 REST API CRUD 간단 구현 (4)-예외처리/handle Exception

이전 내용↓↓↓ 2023.11.13 - [Web Application/Backend] - [REST API] Spring Boot로 REST API CRUD 간단 구현 (3) [REST API] Spring Boot로 REST API CRUD 간단 구현 (3) 이전 내용↓↓↓ 2023.11.11 - [Web Application/Backend] - [REST API] S

im-gonna.tistory.com

 

 

응답 형태를 사용자가 원하는 형태로 받을 수 있도록 ResponseEntity를 커스텀하기!

 

이전에는 get을 통해 특정 cloudvendor의 정보를 불러들일 때 아래와 같이 4가지 속성에 대한 정보만 나왔다.

왜냐하면, 컨트롤러의 get 메서드에서 CloudVendor 서비스의 get메서드를 통해 데이터베이스에 있는 데이터를 가져오기 때문이다.

 

나는 컨트롤러의 get 메서드를 호출하면, 위의 데이터 뿐만아니라 httpStatus와, 특정 메시지도 가져오도록 하고 싶다면??

ResponseEntity를 세가지를 담도록 커스텀해주면 된다!

 

다른 형태로 담고싶다면 그것대로 커스텀해주면 된다.

 

아래 절차를 따라 ResponseEntity를 커스텀하고 다시 get을 통해 확인해보자!

 

💡 ResponseEntity 커스텀하기

 

1. response 패키지를 생성해준 후, ResponseHandler 클래스를 생성해준다.

 

2. ResponseHandler 클래스안에 reponseBuilder 메서드를 정의해준다.

public static ResponseEntity<Object> responseBuilder(
            String message, HttpStatus httpStatus, Object responseObject
    )

 

  • 이 메서드는 responseHandler 객체를 생성하지 않아도 사용할 수 있도록, static으로 선언해준다.
  • ResponseEntity를 사용자 입맛대로 커스텀해줄 것이기 때문에, ResponseEntity를 반환하도록 한다.
  • 이 메서드의 인자로는 string타입의 message와, HttpStstus와, 임의의 데이터인 Object타입의 responseObject를 갖는다.

3. responseBuilder 메서드의 로직은 다음과 같이 동작할 수 있다.

{
        Map<String, Object> response = new HashMap<>();
        response.put("message", message);
        response.put("httpStatus", httpStatus);
        response.put("data", responseObject);

        return new ResponseEntity<>(response, httpStatus);
    }
  • string과 object를 속성으로 갖는 Map을 하나 생성하여 HashMap으로 생성한다.
  • 인자로 받은 것들을 Map에 message, httpStatus, reponseObject로 갖도록 한다.
  • 그리고 ResponseEntity로 map과 httpStatus를 담아 반환한다. 

4. ResponseHandler 클래스의 코드 전문이다.

 

 

💡 커스텀한 ResponseEntity를 반환하도록 컨트롤러 수정하기

 

  • getCloudVendorDetails함수는 원래 url로 특정 vendorId가 들어오면, CloudVendor 엔티티 객체를 반환하도록 되어있었다.
  • 그러나, 지금은 커스텀한 ResponseEntity를 통해, 위와 같이 "특정 메시지"와 HttpStaus.OK와 기존의 데이터인 CloudVendor 엔티티 객체를 responseBuilder메서드의 인자로 넣어 커스텀한 ResponseEnity로 반환되도록 수정해주었다.
  • 이 get 메서드에서 바뀐 부분은 반환타입이 커스텀한 ResponseEnity라는 것이다.

 

💡 결과 확인
  • spring boot를 실행하고, postman에서 C5에 대해서 get mapping 해준다
  • mapping 결과 다음과 같이 data, httpStatus, message가 모두 반환되었다.

  • 이로써 내가 커스텀한대로 Response의 형태가 바뀌어 반환된 것을 확인할 수 있다.

 

↓↓↓ 다음 내용

2023.12.30 - [Web Application/Backend] - [REST API] Spring Boot로 REST API CRUD 간단 구현 (6) - JUnit TEST 기본 설정 및 repository 계층 test 예제

 

[REST API] Spring Boot로 REST API CRUD 간단 구현 (6) - JUnit TEST 기본 설정 및 repository 계층 test 예제

↓↓↓ 이전 내용 2023.12.15 - [Web Application/Backend] - [REST API] Spring Boot로 REST API CRUD 간단 구현 (5)-사용자 정의 ResponseEntity [REST API] Spring Boot로 REST API CRUD 간단 구현 (5)-사용자 정의 ResponseEntity 이전 내

im-gonna.tistory.com

 

반응형
반응형

지난 시간, 간단한 model을 생성하고, 해당 model을 클래스 내에서 직접 생성하고, 클라인언트로부터 받은 정보를 통해 CRUD를 구현해 보았다.
↓↓↓

2023.11.08 - [Web Application/Backend] - [REST API] Spring Boot로 REST API CRUD 간단 구현 (1)

 

[REST API] Spring Boot로 REST API CRUD 간단 구현 (1)

💡 REST API를 사용하여 간단한 CRUD 동작을 구현하기 ✅ 프로젝트 세팅 ✔ Spring Initializer를 이용하여 프로젝트 파일 생성 ✔ Gradle 선택 ✔ 스프링 버전 2.7.x ✔ 자바 버전 11 ❗ 참고로 스프링 버전 3

im-gonna.tistory.com

 

이번에는 직접 MYSQL db를 생성하고 db와 연동해보자.

 

💡 MYSQL, JPA 종속성 추가하기

 

MYSQL과 JPA를 사용하려면 먼저 종속성을 추가해 주어야 한다.

 

여기서 잠깐, JPA란?

> JPA는 "Java Persistence API"의 약자로, Java에서 데이터베이스를 관리하는 표준 인터페이스를 제공하는 API입니다. JPA는 객체와 관계형 데이터베이스 간의 매핑을 처리하고, 객체 지향 프로그래밍(OOP) 언어인 Java와 관계형 데이터베이스 간의 상호 작용을 간소화하는 목적으로 만들어졌습니다.

= 즉, db의 데이터를 가져올 수 있도록 하는 매개체 역할이다.

= 자바의 객체와, 데이터베이스 간의 데이터를 매칭해준다.

 

  • build.gradle 파일에 들어가서 dependencies 부분에 아래와 같이 코드를 추가해준다.

원래는 spring_web이랑 test 밖에 없었으나, 가운데 두 종속성을 추가해주었다.

위는 jpa, 아래는 mysql에 대한 종속성이다.

 

 

💡 MYSQL 연동을 위한 정보를 가진 yml 파일 생성하기

 

yml 파일은 애플리케이션의 설정 정보를 가진다.

resource 디렉토리 하에 application.yml 파일을 생성하고 데이터베이스 연결 정보를 추가해준다.

# database 연동 설정
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    #    각자 PC에 만들어놓은 Database이름을 써야 합니다.
    url: jdbc:mysql://localhost:3306/cloud_vendor?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
    #    mysql에 생성한 사용자 계정 정보를 써야 합니다.
    username: 자신의 db username
    password: 자신의 db pw
  thymeleaf:
    cache: false

  # spring data jpa 설정
  jpa:
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
    open-in-view: false
    show-sql: true
    hibernate:
      ddl-auto: create //초기 설정 시 create로 하고 나중에 db가 완전해지면, update로 바꿔서 사용
#      use-new-id-generator-mappings: false

 

위는 yml에 들어가는 코드이다.

  • datesource의 url에서 cloud_vendor는 이 프로젝트에서 사용하는 db 이름이고, 내 db에 미리 만들어져 있어야 한다.
  • 아래 username과 password는 자신의 db에 맞게 넣어주면 된다.
  • 아래 jpa에서 ddl-auto는 create로 두면 entity로 둔 table이 생성되고, update로 되면 변경사항만 변경된다.
  • 초기에는 보통 create로 둔다.

 

💡 application controller 정상 실행되는지 확인하기

 

build.gradle을 수정하고 난 뒤에는 코끼리 모양을 눌러 다시 build해주어야 변경 사항이 적용된다.

yml 파일을 추가했으므로, 한번 application controller를 실행해 보아서 문제가 없는지 확인한다.

문제가 없다면 잘 진행된 것!

 

다음 회차↓↓↓

2023.11.13 - [Web Application/Backend] - [REST API] Spring Boot로 REST API CRUD 간단 구현 (3)

 

[REST API] Spring Boot로 REST API CRUD 간단 구현 (3)

DB연동에 이어서, db에 있는 정보를 CRUD 처리해보자. 💡 Model을 entity로 설정 model인 CloudVendor를 entity로써 하나의 테이블로 선언해주기 위해, CloudVendor 클래스를 수정해준다. CloudVendor를 Entity로 선언

im-gonna.tistory.com

  

반응형

+ Recent posts