ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Database local dev환경 구성하기(postgreSQL with Docker)
    프로젝트/선착순 쿠폰 발급 시스템 2023. 4. 29. 00:01

    개요

    별다른 설정 없이도 Spring Boot가 지원하는 in-memory H2 Database 덕분에 JPA를 활용하여 API요청 테스트를 수행할 수 있었습니다.

     

    local 환경에는 h2 database를 dev환경에는 postgreSQL로 구성해 보고자 합니다.

     

    application-infra.yml 설정

    ---
    spring:
      profiles:
        active:
          on-profile : local
    
      h2:
        console:
          enabled: true
      jpa:
        database-platform: org.hibernate.dialect.H2Dialect
        hibernate:
          ddl-auto: none
    
      datasource:
        hikari:
          connectionTimeout: 30000
          idleTimeout: 60000
          maxLifetime: 1800000
        url: jdbc:h2:mem:reader
        username: sa
        password: null
        driverClassName: org.h2.Driver
    
    ---
    spring:
      profiles:
        active:
          on-profile : dev
    
      h2:
        console:
          enabled: true
      jpa:
        database-platform: org.hibernate.dialect.H2Dialect
        hibernate:
          ddl-auto: none
    
      datasource:
        hikari:
          connectionTimeout: 30000
          idleTimeout: 60000
          maxLifetime: 1800000
        url: jdbc:h2:mem:reader
        username: sa
        password: null
        driverClassName: org.h2.Driver

    단일 datasource이며 우선 local과 dev의 환경을 h2로 구성해보고자 했습니다.

     

    Local 환경 DB 테스트

    infrastructure 모듈에 테스트를 만들어 보겠습니다.

     

    SpringBootApplication

    @SpringBootApplication(scanBasePackages = ["com.demo.infrastructure"])
    class SpringBootApplication {
    }

    테스트의 Spring Bean scan을 위해서 구성하였습니다.

     

    SignUpTest

    package com.demo.infrastructure.member.signup
    
    import com.demo.domain.member.entity.Member
    import com.demo.infrastructure.member.signup.adapter.MemberPersistenceAdapter
    import com.demo.infrastructure.member.signup.repository.MemberJpaRepository
    import org.junit.jupiter.api.Assertions
    import org.junit.jupiter.api.Test
    import org.springframework.beans.factory.annotation.Autowired
    import org.springframework.boot.test.context.SpringBootTest
    import org.springframework.test.context.ActiveProfiles
    
    @SpringBootTest
    @ActiveProfiles("local")
    internal class SignUpTest @Autowired constructor(
        val memberJpaRepository: MemberJpaRepository,
        val memberPersistenceAdapter: MemberPersistenceAdapter,
    ){
    
        @Test
        fun `초기 데이터베이스 상태는 member를 가지고 있지 않아야 한다`(){
            //given
            val empty = 0
    
            //when
            val memberCount = memberJpaRepository.findAll().size
    
            //then
            Assertions.assertEquals(memberCount, empty)
        }
    
        @Test
        fun `회원을 가입한 경우 회원을 조회할 수 있어야 한다`(){
            //given
            val member = Member.testFixture()
    
            //when
            memberPersistenceAdapter.save(member)
    
            //then
            val memberCount = memberJpaRepository.findAll().size
            Assertions.assertEquals(memberCount, 1)
        }
    }

    ActiveProfiles를 통해 local환경을 테스트하고자 했습니다.

    추후에는 dev로 바꾸어 postgreSQL에서도 테스트하고자 합니다.

     

    위에서 SpringBootApplication을 테스트환경에 만들어두었기 때문에 @SpringBootTest를 수행하면 com.demo.infrastructure 하위 패키지의 bean을 scan 할 수 있게 됩니다.

     

     

    Dev 환경 DB 구축

    docker를 활용하여 postgreSQL을 할 예정입니다.

     

    이전에 kafka를 위해 사용했던 docker-compose.yml에 postgreSQL을 구축했습니다.

    #docker-compose.yml
    version: '2'
    services:
      zookeeper:
        container_name: local-zookeeper
        image: wurstmeister/zookeeper
        ports:
          - "2181:2181"
      kafka:
        container_name: local-kafka
        image: wurstmeister/kafka
        depends_on:
          - zookeeper
        ports:
          - "9092:9092"
        environment:
          KAFKA_ADVERTISED_HOST_NAME: 127.0.0.1
          KAFKA_ADVERTISED_PORT: 9092
          KAFKA_CREATE_TOPICS: "test:1:1"  #topic이름:partition개수:replica개수
          KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock
    
      db:
        container_name: coupon
        image: 'postgres:13.1-alpine'
        ports:
          - "5432:5432"
        environment:
          - POSTGRES_DB=coupon_db
          - POSTGRES_USER=root
          - POSTGRES_PASSWORD=1234

    위의 zookeeper, kafka 부분은 무시하고 db 쪽 설정만 추가해 줍니다.

    postgres 13 docker image를 받아 database이름은 root 비밀번호는 1234로 설정합니다.

     

    application-infra.yml  dev-profile 수정

    spring:
      profiles:
        active:
          on-profile : dev
    
      h2:
        console:
          enabled: true
      jpa:
        database-platform: org.hibernate.dialect.PostgreSQLDialect
        hibernate:
          ddl-auto: none
    
      datasource:
        hikari:
          connectionTimeout: 30000
          idleTimeout: 60000
          maxLifetime: 1800000
        url: jdbc:postgresql://localhost:5432/coupon_db
        username: root
        password: 1234
        driverClassName: org.postgresql.Driver

     

    테스트를 위한 application.yml 작성

    테스트를 위해 테스트하는 부분에 resources를 만들고 application.yml을 작성합니다.

    application-infra.yml과 동일합니다.

    하지만 ddl-auto 부분을 update로 변경합니다

    이유는 현재 JPA entity에 해당하는 Table을 따로 생성해주지 않았기 때문입니다.

     

    Docker-Compose UP

    docker-compose up 명령어를 수행했으나 port binding에서 이미 사용 중이라는 에러가 나왔습니다.

    natstat을 이용하여 5432 port를 조회했으나 사용 중인 어떤 port도 조회되지 않았습니다.

    에러 해결을 위해 docker-compose 관련하여 여러 시도를 해보았지만 재부팅 후 해결되었습니다..

     

    Docker PostgreSQL Clean Up

    docker-compose down --volumes

    volumes 가 계속 저장되기 때문에 이미 생성되어 있다면 계속 데이터가 쌓이게 됩니다.

    만약 clean up을 하고 싶다면 위의 명령어를 통해 해결할 수 있습니다.

     

    gradle 특정(dev) profile만 테스트하도록 하기

    ./gradlew clean test -Pprofile=dev

    dev profile만 test 할 수 있도록 하는 gradlew 명령어입니다.

     

    SignUpTest 

    package com.demo.infrastructure.member.signup
    
    import com.demo.domain.member.entity.Member
    import com.demo.infrastructure.member.signup.adapter.MemberPersistenceAdapter
    import com.demo.infrastructure.member.signup.repository.MemberJpaRepository
    import org.junit.jupiter.api.Assertions
    import org.junit.jupiter.api.Test
    import org.springframework.beans.factory.annotation.Autowired
    import org.springframework.boot.test.context.SpringBootTest
    import org.springframework.test.context.ActiveProfiles
    import org.springframework.transaction.annotation.Transactional
    
    @SpringBootTest
    @ActiveProfiles("dev")
    @Transactional
    internal class SignUpTest @Autowired constructor(
        val memberJpaRepository: MemberJpaRepository,
        val memberPersistenceAdapter: MemberPersistenceAdapter,
    ){
    
        @Test
        fun `초기 데이터베이스 상태는 member를 가지고 있지 않아야 한다`(){
            //given
            val empty = 0
    
            //when
            val memberCount = memberJpaRepository.findAll().size
    
            //then
            Assertions.assertEquals(memberCount, empty)
        }
    
        @Test
        fun `회원을 가입한 경우 회원을 조회할 수 있어야 한다`(){
            //given
            val member = Member.testFixture()
    
            //when
            memberPersistenceAdapter.save(member)
    
            //then
            val memberCount = memberJpaRepository.findAll().size
            Assertions.assertEquals(memberCount, 1)
        }
    }

    이전에 작성하였던 테스트에서 local -> dev로 바꾸어 테스트를 실행해 보면 정상적으로 동작하는 것을 확인할 수 있습니다.

     

    또한 @Transactional 애노테이션을 추가해 테스트가 수행 후 rollback 되도록 만들어 재사용이 가능해졌습니다.

    댓글

Designed by Tistory.