CassandraUnit Test Tutorial – CassandraUnit测试教程

最后修改: 2021年 11月 24日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Apache Cassandra is a powerful open-source NoSQL distributed database. In a previous tutorial, we looked at some of the basics of how to work with Cassandra and Java.

Apache Cassandra是一个强大的开源NoSQL分布式数据库。在之前的教程中,我们了解了如何使用Cassandra 和 Java的一些基本知识。

In this tutorial, we’ll build on the previous one and learn how to write reliable, self-contained unit tests using CassandraUnit.

在本教程中,我们将在前一个教程的基础上,学习如何使用CassandraUnit编写可靠、独立的单元测试。

First, we’ll start by looking at how to get the latest version of CassandraUnit set up and configured. Then we’ll explore several examples of how we can write unit tests that don’t rely on an external database server running.

首先,我们将从如何设置和配置最新版本的 CassandraUnit 开始。然后我们将探讨几个例子,说明我们如何编写不依赖外部数据库服务器运行的单元测试。

And, if you’re running Cassandra in production, you can definitely cut out the complexity of running and maintaining your own server and use the Astra database instead, which is a cloud-based database built on Apache Cassandra.

而且,如果您在生产中运行 Cassandra,您绝对可以省去运行和维护自己的服务器的复杂性,而使用Astra 数据库,这是基于 Apache Cassandra 的云数据库。

2. Dependencies

2.依赖性

Of course, we’ll need to add the standard Datastax Java driver for Apache Cassandra to our pom.xml:

当然,我们需要将Apache Cassandra的标准Datastax Java驱动程序添加到我们的pom.xml中。

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

In order to test our code with an embedded database server, we should also add the cassandra-unit dependency to our pom.xml as well:

为了用嵌入式数据库服务器测试我们的代码,我们还应该将cassandra-unit依赖性也添加到我们的pom.xml中。

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

Now that we have all the necessary dependencies configured, we can start writing our unit tests.

现在我们已经配置了所有必要的依赖关系,我们可以开始编写我们的单元测试。

3. Getting Started

3.入门

Throughout this tutorial, the focus of our tests will be a simple person table that we control via a simple CQL script:

在本教程中,我们测试的重点将是一个简单的人名表,我们通过一个简单的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');

As we’re going to see, CassandraUnit offers several variations to help us write tests, but at the heart of them are several straightforward concepts that we’ll keep repeating:

正如我们将要看到的,CassandraUnit提供了几种变化来帮助我们编写测试,但其核心是几个简单明了的概念,我们将不断地重复。

  • First, we’ll start an embedded Cassandra Server which runs in-memory within our JVM.
  • Then we’ll load our person dataset into the running embedded instance.
  • Finally, we’ll launch a simple query to verify that our data has been loaded correctly.

To conclude this section, a quick word on testing. In general, when writing clean unit or integration tests, we shouldn’t depend on external services that we might not be able to control or might suddenly stop working. This could have adverse effects on our test results.

作为本节的结尾,简单说一下测试的问题。一般来说,在编写干净的单元或集成测试时,我们不应该依赖那些我们可能无法控制或可能突然停止工作的外部服务。这可能会对我们的测试结果产生不利影响。

Similarly, if we’re dependent on an external service, in this case a running Cassandra database, we likely won’t be able to set it up, control it and tear it down in the way we want from our tests.

同样,如果我们依赖于一个外部服务,在这种情况下,一个正在运行的Cassandra数据库,我们很可能无法从我们的测试中以我们想要的方式设置它、控制它和拆毁它。

4. Testing Using a Native Approach

4.使用本地方法进行测试

Let’s start by looking at how to use the native API that comes with CassandraUnit. First, we’ll go ahead and define our unit test and test setup:

让我们先来看看如何使用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"));
    }
}

Let’s walk through the key parts of our test setup. First, we begin by starting an embedded Cassandra server. For this, all we have to do is call the startEmbeddedCassandra() method.

让我们走过我们的测试设置的关键部分。首先,我们开始启动一个嵌入式 Cassandra 服务器。为此,我们所要做的就是调用startEmbeddedCassandra()方法。

This will start our database server using the fixed port 9142:

这将使用固定的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)...

If we prefer to use a randomly available port, we can use the provided Cassandra YAML configuration file:

如果我们喜欢使用一个随机可用的端口,我们可以使用提供的Cassandra YAML 配置文件。

EmbeddedCassandraServerHelper
  .startEmbeddedCassandra(EmbeddedCassandraServerHelper.CASSANDRA_RNDPORT_YML_FILE);

Likewise, we can also pass our own YAML configuration file when starting the server. Of course, this file needs to be in our classpath.

同样地,我们也可以在启动服务器时传递我们自己的YAML配置文件。当然,这个文件需要在我们的classpath中。

Next, we can go ahead and load our people.cql dataset into our database. For this, we use the ClassPathCQLDataSet class, which takes the dataset location and an optional keyspace name.

接下来,我们可以继续将我们的people.cql数据集加载到我们的数据库。为此,我们使用ClassPathCQLDataSet类,它接收数据集的位置和一个可选的关键空间名称。

Now that we have loaded some data, and our embedded server is up and running, we can go ahead and write a simple unit test:

现在我们已经加载了一些数据,而且我们的嵌入式服务器已经启动并运行,我们可以继续编写一个简单的单元测试。

@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"));
}

As we can see, executing a simple query confirms that our test is working correctly. Awesome! We now have a way to write self-contained, independent unit tests using an in-memory Cassandra database.

正如我们所看到的,执行一个简单的查询,证实了我们的测试工作是正确的。棒极了!我们现在有办法使用内存 Cassandra 数据库编写独立的单元测试

Finally, when we tear down our test, we’ll clean our embedded instance:

最后,当我们拆毁我们的测试时,我们将清理我们的嵌入式实例。

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

Executing this will drop all existing keyspaces except for the system keyspace.

执行此操作将放弃所有现有的钥匙空间,除了系统钥匙空间。

5. Testing Using the CassandraUnit Abstract JUnit Test Case

5.使用CassandraUnit抽象JUnit测试案例进行测试

To help simplify the example we saw in the last section, CassandraUnit provides an abstract test case class AbstractCassandraUnit4CQLTestCase, which takes care of the set up and tear down we saw before:

为了帮助简化我们在上一节看到的例子,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"));
    }
}

This time around, by extending the AbstractCassandraUnit4CQLTestCase class, all we need to do is override the getDataSet() method, which returns the CQLDataSet we wish to load.

这次,通过扩展AbstractCassandraUnit4CQLTestCase类,我们需要做的就是覆盖getDataSet()方法,该方法返回我们想要加载的CQLDataSet

Another subtle difference is that from our test, we need to call getSession() to gain access to the Cassandra Java driver.

另一个微妙的区别是,从我们的测试来看,我们需要调用getSession()以获得对Cassandra Java驱动的访问。

6. Testing Using the CassandraCQLUnit JUnit Rule

6.使用CassandraCQLUnit JUnit规则进行测试

If we don’t want to force our tests to extend AbstractCassandraUnit4CQLTestCase, then luckily CassandraUnit also provides a standard JUnit Rule:

如果我们不想强制我们的测试扩展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"));
    }
}

All we have to do is declare a CassandraCQLUnit field in our test, which is a standard JUnit @Rule. This rule will prepare and manage the life cycle of our Cassandra Server.

我们所要做的就是在我们的测试中声明一个CassandraCQLUnit字段,这是一个标准的JUnit@Rule。这个规则将准备和管理我们的Cassandra服务器的生命周期。

7. Working With Spring

7.使用Spring工作

Typically we might integrate Cassandra with Spring in our projects. Fortunately, CassandraUnit also provides support for working with the Spring TestContext Framework.

通常情况下,我们可能会在项目中集成Cassandra 与 Spring。幸运的是,CassandraUnit还提供了对与Spring TestContext框架合作的支持。

To take advantage of this support, we need to add the cassandra-unit-spring Maven dependency to our project:

为了利用这一支持,我们需要将cassandra-unit-spring Maven依赖性添加到我们的项目中。

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

Now we have access to a number of annotations and classes that we can use from our tests. Let’s go ahead and write a test that uses the most basic of Spring configurations:

现在我们可以访问一些注解和类,我们可以从我们的测试中使用。让我们继续写一个测试,使用最基本的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"));
    }
}

Let’s walk through the key parts of our test. First, we start by decorating our test class with two pretty standard Spring related annotations:

让我们走过我们测试的关键部分。首先,我们先用两个相当标准的Spring相关注解来装饰我们的测试类。

  • The @RunWith(SpringJUnit4ClassRunner.class) annotation will ensure that our test embeds Spring’s TestContextManager into our test, giving us access to the Spring ApplicationContext.
  • We also specify a custom TestExecutionListener, called CassandraUnitTestExecutionListener, which is responsible for starting and stopping our server and finding other CassandraUnit annotations.

Here comes the crucial part; we use the @EmbeddedCassandra annotation to inject an instance of an embedded Cassandra server into our tests. Moreover, there are several properties available that we can use to further configure the embedded database server:

关键部分来了;我们使用@EmbeddedCassandra注解将一个嵌入式Cassandra服务器的实例注入我们的测试中。此外,还有几个可用的属性,我们可以用它们来进一步配置嵌入式数据库服务器。

  • configuration – a different Cassandra configuration file
  • clusterName – the name of the cluster
  • host – the host of our cluster
  • port – the port used by our cluster

We’ve kept things simple here, opting for the default values by omitting these properties from our declaration.

我们在这里保持简单,选择默认值,从我们的声明中省略这些属性。

For the final piece of the puzzle, we use the @CassandraDataSet annotation to load the same CQL dataset that we’ve seen previously. In the same way as before, we can send a query to verify the contents of our database are correct.

对于拼图的最后一块,我们使用@CassandraDataSet注解来加载我们之前看到的相同的CQL数据集。和以前一样,我们可以发送一个查询来验证我们数据库的内容是否正确。

8. Conclusion

8.结论

In this article, we learned several ways we can work with CassandraUnit to write stand-alone unit tests using an embedded instance of Apache Cassandra. We also discussed how we can work with Spring from our unit tests as well.

在这篇文章中,我们学习了几种方法,我们可以与CassandraUnit合作,使用Apache Cassandra的嵌入式实例编写独立的单元测试。我们还讨论了如何从我们的单元测试中与Spring合作。

As always, the full source code of the article is available over on GitHub.

一如既往,文章的完整源代码可在GitHub上获得