1. 개요

Apache Cassandra 는 강력한 오픈 소스 NoSQL 분산 데이터베이스입니다. 이전 사용방법(예제)에서 Cassandra 및 Java 로 작업하는 방법에 대한 몇 가지 기본 사항을 살펴보았습니다 .

이 예제에서는  이전 예제을 기반으로 CassandraUnit 을 사용하여 신뢰할 수 있고 독립적인 단위 테스트를 작성하는 방법을 배웁니다 .

먼저 최신 버전의 CassandraUnit을 설정하고 구성하는 방법부터 살펴보겠습니다. 그런 다음 실행 중인 외부 데이터베이스 서버에 의존하지 않는 단위 테스트를 작성하는 방법에 대한 몇 가지 예를 살펴보겠습니다.

또한 프로덕션에서 Cassandra를 실행하는 경우 자체 서버를 실행하고 유지 관리하는 복잡성을 확실히 제거하고 대신 Apache Cassandra에 구축된 클라우드 기반 데이터베이스 인 Astra 데이터베이스 를 사용할 수 있습니다.

2. 의존성

물론 Apache Cassandra용  표준 Datastax Java 드라이버 를 pom.xml 에 추가해야 합니다 .

<dependency>
    <groupId>com.datastax.oss</groupId>
    <artifactId>java-driver-core</artifactId>
    <version>4.13.0</version>
</dependency>

임베디드 데이터베이스 서버로 코드를 테스트하려면 pom.xml 에도 cassandra-unit 의존성을 추가해야 합니다.

<dependency>
    <groupId>org.cassandraunit</groupId>
    <artifactId>cassandra-unit</artifactId>
    <version>4.3.1.0</version>
    <scope>test</scope>
</dependency>

이제 필요한 모든 의존성을 구성했으므로 단위 테스트 작성을 시작할 수 있습니다.

3. 시작하기

이 사용방법(예제) 전체에서 테스트의 초점은 간단한 CQL 스크립트 를 통해 제어하는 ​​간단한 개인 테이블입니다 .

CREATE TABLE person(
    id varchar,
    name varchar,
    PRIMARY KEY(id));

INSERT INTO person(id, name) values('1234','Eugen');
INSERT INTO person(id, name) values('5678','Michael');

앞으로 살펴보겠지만 CassandraUnit은 테스트를 작성하는 데 도움이 되는 몇 가지 변형을 제공하지만 그 중심에는 계속해서 반복할 몇 가지 간단한 개념이 있습니다.

  • 먼저 JVM 내에서 메모리 내에서 실행되는 임베디드 Cassandra 서버를 시작합니다.
  • 그런 다음 개인 데이터 세트를 실행 중인 임베디드 인스턴스에 로드합니다.
  • 마지막으로 간단한 쿼리를 시작하여 데이터가 올바르게 로드되었는지 확인합니다.

이 섹션을 마무리하기 위해 테스트에 대한 간략한 설명입니다. 일반적으로 깨끗한 단위 또는 통합 테스트를 작성할 때 제어할 수 없거나 갑자기 작동이 중지될 수 있는 외부 서비스에 의존해서는 안 됩니다 . 이는 테스트 결과에 악영향을 미칠 수 있습니다.

마찬가지로 외부 서비스에 의존하는 경우(이 경우에는 실행 중인 Cassandra 데이터베이스) 테스트에서 원하는 방식으로 설정, 제어 및 해체할 수 없습니다.

4. 기본 접근 방식을 사용한 테스트

CassandraUnit과 함께 제공되는 기본 API를 사용하는 방법부터 살펴보겠습니다. 먼저 단위 테스트 및 테스트 설정을 정의합니다.

public class NativeEmbeddedCassandraUnitTest {

    private CqlSession session;

    @Before
    public void setUp() throws Exception {
        EmbeddedCassandraServerHelper.startEmbeddedCassandra();
        session = EmbeddedCassandraServerHelper.getSession();
        new CQLDataLoader(session).load(new ClassPathCQLDataSet("people.cql", "people"));
    }
}

테스트 설정의 주요 부분을 살펴보겠습니다. 먼저 임베디드 Cassandra 서버를 시작합니다. 이를 위해 startEmbeddedCassandra() 메서드를 호출하기만 하면 됩니다.

그러면 고정 포트 9142를 사용하여 데이터베이스 서버가 시작됩니다.

11:13:36.754 [pool-2-thread-1] INFO  o.apache.cassandra.transport.Server
  - Starting listening for CQL clients on localhost/127.0.0.1:9142 (unencrypted)...

임의로 사용 가능한 포트를 사용하려는 경우 제공된 Cassandra YAML 구성 파일을 사용할 수 있습니다.

EmbeddedCassandraServerHelper
  .startEmbeddedCassandra(EmbeddedCassandraServerHelper.CASSANDRA_RNDPORT_YML_FILE);

마찬가지로 서버를 시작할 때 자체 YAML 구성 파일을 전달할 수도 있습니다. 물론 이 파일은 클래스 경로에 있어야 합니다.

다음으로 계속해서 people.cql 데이터 세트를 데이터베이스에 로드할 수 있습니다. 이를 위해 데이터 세트 위치와 선택적 키스페이스 이름 을 사용하는 ClassPathCQLDataSet 클래스를 사용합니다.

이제 일부 데이터를 로드했고 임베디드 서버가 실행 중이므로 간단한 단위 테스트를 작성할 수 있습니다.

@Test
public void givenEmbeddedCassandraInstance_whenStarted_thenQuerySuccess() throws Exception {
    ResultSet result = session.execute("select * from person WHERE id=1234");
    assertThat(result.iterator().next().getString("name"), is("Eugen"));
}

보시다시피 간단한 쿼리를 실행하면 테스트가 올바르게 작동하는지 확인할 수 있습니다. 대박! 이제 메모리 내 Cassandra 데이터베이스를 사용하여 자체 포함된 독립 단위 테스트를 작성할 수 있습니다 .

마지막으로 테스트를 해체할 때 포함된 인스턴스를 정리합니다.

@After
public void tearDown() throws Exception {
    EmbeddedCassandraServerHelper.cleanEmbeddedCassandra();
}

이를 실행하면 시스템 키 스페이스를 제외한 모든 기존 키스페이스가 삭제됩니다 .

5. CassandraUnit 추상 JUnit 테스트 사례를 사용한 테스트

이전 섹션에서 본 예제를 단순화하기 위해 CassandraUnit은 추상 테스트 사례 클래스 인 AbstractCassandraUnit4CQLTestCase를 제공합니다. 이 클래스 는 이전에 본 설정 및 해제를 처리합니다.

public class AbstractTestCaseWithEmbeddedCassandraUnitTest
  extends AbstractCassandraUnit4CQLTestCase {

    @Override
    public CQLDataSet getDataSet() {
        return new ClassPathCQLDataSet("people.cql", "people");
    }

    @Test
    public void givenEmbeddedCassandraInstance_whenStarted_thenQuerySuccess()
      throws Exception {
        ResultSet result = this.getSession().execute("select * from person WHERE id=1234");
        assertThat(result.iterator().next().getString("name"), is("Eugen"));
    }
}

이번에는 AbstractCassandraUnit4CQLTestCase 클래스 를 확장하여 로드하려는 CQLDataSet 을 반환하는 getDataSet() 메서드를 재정의하기만 하면 됩니다.

또 다른 미묘한 차이점은 테스트에서 Cassandra Java 드라이버에 액세스하려면 getSession()  을 호출해야 한다는 것입니다.

6. CassandraCQLUnit JUnit 규칙 을 사용한 테스트

테스트가 AbstractCassandraUnit4CQLTestCase 를 확장하도록 강제하고 싶지 않은 경우 다행히도 CassandraUnit은 표준 JUnit 규칙 도 제공합니다 .

public class JUnitRuleWithEmbeddedCassandraUnitTest {

    @Rule
    public CassandraCQLUnit cassandra = new CassandraCQLUnit(new ClassPathCQLDataSet("people.cql", "people"));

    @Test
    public void givenEmbeddedCassandraInstance_whenStarted_thenQuerySuccess() throws Exception {
        ResultSet result = cassandra.session.execute("select * from person WHERE id=5678");
        assertThat(result.iterator().next().getString("name"), is("Michael"));
    }
}

우리가 해야 할 일은 테스트에서 표준 JUnit @Rule 인 CassandraCQLUnit 필드를 선언하는 것 입니다. 이 규칙은 Cassandra Server의 수명 주기를 준비하고 관리합니다.

7. 스프링 작업

일반적으로 프로젝트에서 Cassandra를 Spring과 통합할 수 있습니다. 다행스럽게도 CassandraUnit은 Spring TestContext Framework 작업을 지원합니다.

이 지원을 활용하려면 프로젝트에 cassandra-unit-spring Maven 의존성을 추가해야 합니다.

<dependency>
    <groupId>org.cassandraunit</groupId>
    <artifactId>cassandra-unit-spring</artifactId>
    <version>4.3.1.0</version>
    <scope>test</scope>
</dependency>

이제 테스트에서 사용할 수 있는 여러 어노테이션 및 클래스에 액세스할 수 있습니다. 가장 기본적인 Spring 구성을 사용하는 테스트를 작성해 보겠습니다.

@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({ CassandraUnitTestExecutionListener.class })
@CassandraDataSet(value = "people.cql", keyspace = "people")
@EmbeddedCassandra
public class SpringWithEmbeddedCassandraUnitTest {

    @Test
    public void givenEmbeddedCassandraInstance_whenStarted_thenQuerySuccess() throws Exception {
        CqlSession session = EmbeddedCassandraServerHelper.getSession();

        ResultSet result = session.execute("select * from person WHERE id=1234");
        assertThat(result.iterator().next().getString("name"), is("Eugen"));
    }
}

테스트의 핵심 부분을 살펴보겠습니다. 먼저 테스트 클래스를 두 가지 표준 Spring 관련 어노테이션으로 장식하는 것으로 시작합니다.

  • @RunWith(SpringJUnit4ClassRunner.class) 어노테이션은 테스트가 Spring의 TestContextManager 테스트에 포함하도록 하여 Spring ApplicationContext에 대한 액세스를 제공합니다.
  • 또한 CassandraUnitTestExecutionListener 라는 사용자 지정 TestExecutionListener 를 지정합니다. CassandraUnitTestExecutionListener 는 서버 시작 및 중지와 다른 CassandraUnit 어노테이션 찾기를 담당합니다.

여기에 중요한 부분이 있습니다. @EmbeddedCassandra 어노테이션을 사용 하여 임베디드 Cassandra 서버의 인스턴스를 테스트에 주입합니다 . 또한 임베디드 데이터베이스 서버를 추가로 구성하는 데 사용할 수 있는 몇 가지 속성이 있습니다.

  • 구성 – 다른 Cassandra 구성 파일
  • clusterName – 클러스터의 이름
  • 호스트 – 클러스터의 호스트
  • 포트 – 클러스터에서 사용하는 포트

여기서는 선언에서 이러한 속성을 생략하여 기본값을 선택하여 간단하게 유지했습니다.

퍼즐의 마지막 조각을 위해 @CassandraDataSet 어노테이션을 사용하여 이전에 본 것과 동일한 CQL 데이터 세트를 로드합니다. 이전과 같은 방식으로 데이터베이스의 내용이 올바른지 확인하기 위해 쿼리를 보낼 수 있습니다.

8. 결론

이 기사에서는 Apache Cassandra의 임베디드 인스턴스를 사용하여 독립 실행형 단위 테스트를 작성하기 위해 CassandraUnit과 함께 작업할 수 있는 몇 가지 방법을 배웠습니다. 또한 단위 테스트에서 Spring과 작업하는 방법에 대해서도 논의했습니다.

언제나처럼 기사의 전체 소스 코드는  GitHub에서 확인할 수 있습니다 .