Статьи

Выпущена NoSQLUnit 0.3.0

Введение

Модульное тестирование — это метод, с помощью которого проверяется самая маленькая тестируемая часть приложения. Модульные тесты должны соответствовать ПЕРВЫМ правилам; Это быстрые, изолированные, повторяемые, самоутвержденные и своевременные.
Странно думать о приложении JEE без уровня персистентности (типичные реляционные базы данных или новые базы данных NoSQL ), поэтому будет интересно написать модульные тесты уровня персистентности. Когда мы пишем модульные тесты уровня персистентности, мы должны сосредоточиться на том, чтобы не нарушать две основные концепции правил FIRST , быстрое и изолированное.

Наши тесты будут быстрыми, если они не обращаются ни к сети, ни к файловой системе, а в случае персистентных систем сеть и файловая система являются наиболее используемыми ресурсами. В случае RDBMS (SQL) существует много баз данных Java в памяти, таких как Apache Derby , H2 или HSQLDB . Эти базы данных, как следует из их названия, встроены в вашу программу, а данные хранятся в памяти, поэтому ваши тесты все еще бывают быстрыми. Проблема в системах NoSQL из-за их неоднородности. Некоторые системы работают с использованием подхода Document (например, MongoDb ), другие — Column (например, Hbase ) или Graph (например, Neo4J ). По этой причине поставщик должен предоставить режим оперативной памяти, а универсального решения не существует.

Наши тесты должны быть изолированы от самих себя. Недопустимо, чтобы один метод испытаний изменял результат другого метода испытаний. В случае тестов на постоянство этот сценарий возникает, когда предыдущий метод теста вставляет запись в базу данных, и следующее выполнение метода теста находит изменение. Поэтому перед выполнением каждого теста база данных должна находиться в известном состоянии. Обратите внимание, что если ваш тест обнаружил базу данных в известном состоянии, тест будет повторяться, если утверждение теста зависит от предыдущего выполнения теста, каждое выполнение будет уникальным. Для однородных систем, таких как СУБД , DBUnit существует для поддержания базы данных в известном состоянии перед каждым выполнением. Но для гетерогенных систем NoSQL подобной среды DBUnit не существует .

NoSQLUnit решает эту проблему, предоставляя расширение JUnit, которое помогает нам управлять жизненным циклом систем NoSQL , а также заботиться о поддержании баз данных в известном состоянии.

NoSQLUnit

NoSQLUnit — это расширение JUnit для упрощения написания модульных и интеграционных тестов систем, в которых используется серверная часть NoSQL, и состоит из двух наборов правил и группы аннотаций.
Первый набор правил предназначен для управления жизненным циклом базы данных; есть два для каждого поддерживаемого бэкэнда.

  • Первый (если это возможно) — это режим в памяти. Этот режим заботится о запуске и остановке системы базы данных в режиме «в памяти». Этот режим обычно используется во время выполнения модульного тестирования.
  • Второй — управляемый режим. Этот режим отвечает за запуск NoSQL- сервера, но как удаленный процесс (на локальной машине) и его остановку. Обычно это используется во время выполнения интеграционного тестирования.

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

Обратите внимание, что поскольку базы данных NoSQL неоднородны, каждая система потребует своей собственной реализации.
И, наконец, предоставляются две аннотации, @UsingDataSet и @ShouldMatchDataSet , (большое спасибо аркиллианцам за имя) для указания местоположения наборов данных и ожидаемых наборов данных.

Пример MongoDb

Теперь я собираюсь объяснить очень простой пример того, как использовать NoSQLUnit, для полного объяснения всех предоставленных функций, пожалуйста, прочитайте документацию по ссылке или загрузите в формате PDF.
Чтобы использовать NoSQLUnit с MongoDb, вам нужно только добавить следующую зависимость:

1
2
3
4
5
<dependency>
 <groupId>com.lordofthejars<groupId>
 <artifactId>nosqlunit-mongodb<artifactId>
 <version>0.3.0<version>
<dependency>

Первый шаг — определить, какая стратегия управления жизненным циклом необходима для ваших тестов. В зависимости от типа выполняемого вами теста (модульный тест, интеграционный тест, тест развертывания и т. Д.) Вам потребуется подход в памяти , управляемый подход или удаленный подход.

В этом примере мы собираемся использовать управляемый подход с использованием правила ManagedMongoDb ), но отметим, что также поддерживается управление MongoDb в памяти (см. Документацию как).

Следующим шагом является настройка правила Mongodb, отвечающего за поддержание базы данных MongoDb в известном состоянии путем вставки и удаления определенных наборов данных. Вы должны зарегистрировать класс правил MongoDbRule JUnit , для которого требуется параметр конфигурации с такой информацией, как имя хоста, порт или имя базы данных.

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

Давайте посмотрим код:

Прежде всего, это простой класс POJO, который будет использоваться как класс модели:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class Book {
 
 private String title;
 
 private int numberOfPages;
 
 public Book(String title, int numberOfPages) {
  super();
  this.title = title;
  this.numberOfPages = numberOfPages;
 }
 
 public void setTitle(String title) {
  this.title = title;
 }
 
 public void setNumberOfPages(int numberOfPages) {
  this.numberOfPages = numberOfPages;
 }
 
 
 public String getTitle() {
  return title;
 }
 
 public int getNumberOfPages() {
  return numberOfPages;
 }
}

Следующий бизнес-класс отвечает за управление доступом к серверу MongoDb :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
public class BookManager {
 
 private static final Logger LOGGER = LoggerFactory.getLogger(BookManager.class);
 
 private static final MongoDbBookConverter MONGO_DB_BOOK_CONVERTER = new MongoDbBookConverter();
 private static final DbObjectBookConverter DB_OBJECT_BOOK_CONVERTER = new DbObjectBookConverter();
 
 
 private DBCollection booksCollection;
 
 public BookManager(DBCollection booksCollection) {
  this.booksCollection = booksCollection;
 }
 
 public void create(Book book) {
  DBObject dbObject = MONGO_DB_BOOK_CONVERTER.convert(book);
  booksCollection.insert(dbObject);
 }
}

И теперь пришло время для тестирования. В следующем тесте мы собираемся проверить правильность вставки книги в базу данных.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.lordofthejars.nosqlunit.demo.mongodb;
 
public class WhenANewBookIsCreated {
 
 @ClassRule
 public static ManagedMongoDb managedMongoDb = newManagedMongoDbRule().mongodPath('optmongo').build();
 
 @Rule
 public MongoDbRule remoteMongoDbRule = new MongoDbRule(mongoDb().databaseName('test').build());
 
 @Test
 @UsingDataSet(locations='initialData.json', loadStrategy=LoadStrategyEnum.CLEAN_INSERT)
 @ShouldMatchDataSet(location='expectedData.json')
 public void book_should_be_inserted_into_repository() {
 
  BookManager bookManager = new BookManager(MongoDbUtil.getCollection(Book.class.getSimpleName()));
 
  Book book = new Book('The Lord Of The Rings', 1299);
  bookManager.create(book);
 }
 
}

Обратите внимание, что прежде всего мы создаем с помощью аннотации ClassRule управляемое соединение с сервером MongoDb . В этом случае мы настраиваем путь MongoDb программным способом , но также можно установить его из переменной среды MONGO_HOME . Смотрите здесь полное описание всех доступных параметров.

Это правило будет выполнено при загрузке теста и запустит экземпляр MongoDb . Также отключит сервер, когда все тесты будут выполнены.

Следующее правило выполняется перед любым тестовым методом и отвечает за поддержание базы данных в известном состоянии. Обратите внимание, что мы настраиваем только рабочую базу данных, в данном случае тестовую .

И, наконец, мы аннотируем метод test с помощью @UsingDataSet, указывающего, где найти данные, которые нужно вставить перед выполнением каждого теста, и @ShouldMatchDataSet, определяющий местонахождение ожидаемого набора данных.

1
2
3
4
5
6
{
 'Book':
 [
  {'title':'The Hobbit','numberOfPages':293}
 ]
}
1
2
3
4
5
6
7
{
 'Book':
 [
  {'title':'The Hobbit','numberOfPages':293},
  {'title':'The Lord Of The Rings','numberOfPages':1299}
 ]
}

Мы устанавливаем начальный набор данных в файле initialData.json, расположенном по адресу classpath com / lordofthejars / nosqlunit / demo / mongodb / initialData.json, и ожидаемом наборе данных с именем Ожидаемые данные.json .

Финальные заметки

Хотя NoSQLUnit находится на ранних стадиях, часть MongoDb почти завершена, в следующих выпусках будут поддерживаться новые функции и, конечно, новые базы данных. Следующими NoSQL- поддерживаемыми движками станут Neo4J , Cassandra , HBase и CouchDb .

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

И, наконец, любые ваши предложения, рекомендации или советы будут приветствоваться.

Продолжай учиться!

Полный код

Ссылка: NoSQLUnit 0.3.0 Выпущено нашим партнером по JCG Алексом Сото в блоге One Jar To Rule All .