Перейти к основному содержимому

Учебник по тестированию CassandraUnit

· 7 мин. чтения

1. Обзор

Apache Cassandra — это мощная распределенная база данных NoSQL с открытым исходным кодом. В предыдущем уроке мы рассмотрели некоторые основы работы с Cassandra и Java .

В этом руководстве мы будем основываться на предыдущем и узнаем, как писать надежные автономные модульные тесты с использованием CassandraUnit .

Во-первых, мы начнем с того, как установить и настроить последнюю версию CassandraUnit. Затем мы рассмотрим несколько примеров того, как мы можем написать модульные тесты, которые не полагаются на работающий внешний сервер базы данных.

И, если вы используете Cassandra в производственной среде, вы определенно можете упростить запуск и обслуживание собственного сервера и вместо этого использовать базу данных Astra , которая представляет собой облачную базу данных, построенную на Apache Cassandra.

2. Зависимости

Конечно, нам нужно добавить стандартный Java-драйвер Datastax для Apache Cassandra в наш pom.xml :

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

Чтобы протестировать наш код со встроенным сервером базы данных, мы также должны добавить зависимость cassandra -unit в наш pom.xml :

<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','ForEach');
INSERT INTO person(id, name) values('5678','Michael');

Как мы увидим, CassandraUnit предлагает несколько вариантов, помогающих нам писать тесты, но в основе их лежит несколько простых концепций, которые мы будем повторять:

  • Во-первых, мы запустим встроенный сервер Cassandra, который работает в памяти внутри нашей JVM.
  • Затем мы загрузим наш набор данных о людях в работающий встроенный экземпляр.
  • Наконец, мы запустим простой запрос, чтобы убедиться, что наши данные были загружены правильно.

В заключение этого раздела несколько слов о тестировании. В общем, при написании чистых модульных или интеграционных тестов мы не должны зависеть от внешних служб, которые мы не можем контролировать или которые могут внезапно перестать работать . Это может отрицательно сказаться на результатах наших тестов.

Точно так же, если мы зависим от внешней службы, в данном случае от работающей базы данных Cassandra, мы, скорее всего, не сможем настроить ее, контролировать и отключить так, как мы хотим в наших тестах.

4. Тестирование с использованием нативного подхода

Давайте начнем с рассмотрения того, как использовать собственный API, поставляемый с CassandraUnit. Во-первых, мы продолжим и определим наш модульный тест и настройку теста:

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

Как мы видим, выполнение простого запроса подтверждает, что наш тест работает правильно. Потрясающий! Теперь у нас есть способ писать автономные, независимые модульные тесты, используя базу данных Cassandra в памяти .

Наконец, когда мы разорвем наш тест, мы очистим наш встроенный экземпляр:

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

Выполнение этого приведет к удалению всех существующих пространств ключей, кроме системного пространства ключей.

5. Тестирование с использованием тестового примера CassandraUnit Abstract 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("ForEach"));
}
}

На этот раз, расширив класс AbstractCassandraUnit4CQLTestCase , все, что нам нужно сделать, это переопределить метод getDataSet() , который возвращает CQLDataSet , который мы хотим загрузить.

Еще одно тонкое отличие состоит в том, что в нашем тесте нам нужно вызвать getSession() , чтобы получить доступ к драйверу Java Cassandra.

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

Все, что нам нужно сделать, это объявить поле CassandraCQLUnit в нашем тесте, которое является стандартным JUnit @Rule . Это правило будет подготавливать и управлять жизненным циклом нашего сервера Cassandra.

7. Работа с пружиной

Обычно мы можем интегрировать Cassandra со Spring в наши проекты. К счастью, CassandraUnit также поддерживает работу с Spring TestContext Framework.

Чтобы воспользоваться этой поддержкой, нам нужно добавить в наш проект зависимость Maven cassandra-unit-spring :

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

Давайте пройдемся по ключевым частям нашего теста. Во-первых, мы начнем с украшения нашего тестового класса двумя довольно стандартными аннотациями, связанными со Spring:

  • Аннотация @RunWith (SpringJUnit4ClassRunner.class) гарантирует, что наш тест встраивает TestContextManager Spring в наш тест, предоставляя нам доступ к Spring ApplicationContext.
  • Мы также указываем собственный TestExecutionListener, называемый CassandraUnitTestExecutionListener, который отвечает за запуск и остановку нашего сервера и поиск других аннотаций CassandraUnit.

Здесь наступает решающая часть; мы используем аннотацию @EmbeddedCassandra для внедрения экземпляра встроенного сервера Cassandra в наши тесты . Кроме того, есть несколько доступных свойств, которые мы можем использовать для дальнейшей настройки встроенного сервера базы данных:

  • конфигурация — другой файл конфигурации Cassandra
  • clusterName — имя кластера
  • host — хост нашего кластера
  • port — порт, используемый нашим кластером

Здесь мы упростили ситуацию, выбрав значения по умолчанию, исключив эти свойства из нашего объявления.

В качестве последней части головоломки мы используем аннотацию @CassandraDataSet для загрузки того же набора данных CQL, который мы видели ранее. Как и раньше, мы можем отправить запрос, чтобы проверить правильность содержимого нашей базы данных.

8. Заключение

В этой статье мы узнали о нескольких способах работы с CassandraUnit для написания автономных модульных тестов с использованием встроенного экземпляра Apache Cassandra. Мы также обсудили, как мы можем работать с Spring из наших модульных тестов.

Как всегда, полный исходный код статьи доступен на GitHub .