Software Engineering/[BE] Spring Boot (Java)

[Spring Boot] H2GIS와 QueryDSL을 사용한 단위 테스트

devhrkim 2024. 6. 22. 19:43

목차

  • 운영/개발 환경 vs 단위 테스트 환경
  • 설정 코드
  • 샘플 코드

[운영/개발 환경 vs 단위 테스트 환경]

실제 개발 환경에서는 postgresql에 postgis를 확장해서 사용했는데 Spring Boot에서 테스트 할 때는 실제 운영/개발 서버 DB를 사용하지 않고 인 메모리(in-memory) DB를 사용한다.

 

주로 사용하는 인 메모리 DB는 H2, HSQLDB(HyperSQL Database), Apache Derby가 있다. 그 중에서 나는 H2 Database를 사용했다.

 

실제 운영/개발 서버 환경에서 postgresql에 postgis를 확장해서 사용한 것 처럼 테스트 환경에서도 gis 함수를 사용하려면 H2 Database에 H2GIS를 추가해야한다. (예를들면 ST_AsGeojson 함수 사용가능해야 함) 아래는 그 환경 설정과 샘플 코드이다.

 

[설정 코드]

build.gradle

dependencies {
    implementation (
        "org.springframework.boot:spring-boot-starter-data-jpa",
        "org.springframework.boot:spring-boot-starter-web",
        "org.projectlombok:lombok:1.18.28",
        "org.postgresql:postgresql:42.6.2",
        "com.querydsl:querydsl-jpa:5.0.0:jakarta",
        "org.hibernate.orm:hibernate-spatial:6.4.8.Final"
    )
    runtimeOnly (
        "com.h2database:h2",
        "org.locationtech.jts:jts-core:1.18.1"
    )
    annotationProcessor (
        "org.projectlombok:lombok:1.18.28",
        "com.querydsl:querydsl-apt:5.0.0:jakarta",
        "jakarta.annotation:jakarta.annotation-api",
        "jakarta.persistence:jakarta.persistence-api"
    )
    testImplementation (
        "org.springframework.boot:spring-boot-starter-test",
        "org.orbisgis:h2gis:2.1.0"
    )
}

 

 

application.properties

#Test DB
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.sql.init.schema-locations=classpath:scripts/init-h2gis.sql
spring.jpa.hibernate.ddl-auto=create-drop

 

 

resources/scripts/init-h2gis.sql

CREATE ALIAS IF NOT EXISTS H2GIS_SPATIAL FOR "org.h2gis.functions.factory.H2GISFunctions.load";
CALL H2GIS_SPATIAL();

 

[샘플 코드]

@DataJpaTest
class AreaManagementRepositoryCustomImplTest {
    @PersistenceContext
    private EntityManager entityManager;
    @Test
    public void findById() {
        // given
        String geomStr = "MULTIPOLYGON (((x1 y1, x2 y2, x3 y3, x4 y4, x1 y1)))";
        String wktStr = "POINT (x1 y1)";
        AreaManagement areaManagement = AreaManagement.builder()
            .id(1)
            .geom(convertStringToGeometry(geomStr))
            .businessId("18")
            .businessCode("99")
            .businessName("Sample Project in Sejong City")
            .managerName("John Doe")
            .registrationDate(LocalDate.of(2023, 5, 15))
            .closingDate(LocalDate.of(2023, 12, 31))
            .wktGeometry(convertStringToGeometry(wktStr))
            .build();

        // when
        entityManager.merge(areaManagement);
        entityManager.flush();
        entityManager.clear();

        // then
        int testId = 1;
        JPAQueryFactory queryFactory = new JPAQueryFactory(entityManager);
        QAreaManagement qAreaManagement = QAreaManagement.areaManagement;
        Tuple tuple = queryFactory.select(qAreaManagement,
                Expressions.stringTemplate("FUNCTION('ST_AsGeoJSON', {0})", qAreaManagement.wktGeometry).as("geojson"),
                Expressions.stringTemplate("FUNCTION('ST_AsText', FUNCTION('ST_Centroid', {0}))", qAreaManagement.geom).as("centroid"))
            .from(qAreaManagement)
            .where(qAreaManagement.id.eq(testId))
            .orderBy(qAreaManagement.id.asc())
            .fetchOne();

        Assertions.assertThat(tuple).isNotNull();
        JsonNode geojsonNode = convertStringToGeojson(tuple.get(1, String.class));

        Assertions.assertThat(geojsonNode).isNotNull();
        Assertions.assertThat(tuple.get(2, String.class)).isEqualTo("POINT (x1 y1)");
    }
}

 

여기에서 geometry 값은 x1, y1으로 적었는데 사용할 때 실제 좌표 값을 입력하면된다.

 

* English Version

medium url: https://medium.com/@dev.hr.kim/unit-test-using-h2gis-and-query-dsl-in-spring-boot-5409cb1570f5