Статьи

Легко издеваться над вашей базой данных

Разработка через тестирование — это нечто замечательное! Установив его в своей организации, вы начнете:

  • Значительно улучшите свое качество (вещи ломаются реже)
  • Значительно улучшите ваши процессы (вещи можно изменить легче)
  • Значительно улучшите свою атмосферу для разработчиков (дела интереснее)

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

  • автоматизированными юнит-тестами
  • автоматизированными интеграционными тестами
  • ручными «тестами на дым»
  • ручными «приемочными испытаниями»
  • не за что

Нахождение этого соотношения может стать основанием для горячих религиозных дискуссий. Я скоро напишу в блоге о своем собственном мнении на эту тему. Однако в этом посте мы сосредоточимся на первом виде тестирования: модульных тестах .

Модульное тестирование вашего доступа к данным

Когда задействованы базы данных, люди, вероятно, быстро перейдут к написанию интеграционных тестов, потому что все, что им нужно сделать, это создать небольшую тестовую базу данных Derby, H2 или HSQLDB (или другую) и выполнить пару запросов на настройку данных до фактического тест. Надеемся, что их программный модуль не заметит разницы с продуктивной средой, и вся система может быть протестирована как черный ящик. Преимущество этого в том, что ваши тесты могут быть написаны таким образом, чтобы проверять ваши бизнес-требования, ваши пользовательские истории или как вы их называете. Пока что теория.

Когда эти тесты интеграции баз данных накапливаются, становится все труднее оградить их друг от друга. Избегать взаимозависимостей и в то же время избегать дорогостоящих настроек базы данных сложно. Вы не сможете запустить весь набор тестов сразу после сборки / фиксации. Вам нужны ночные сборки, еженедельные сборки. Но модульное тестирование уровня доступа к данным не намного проще! Потому что JDBC — ужасный API для насмешек. Существует множество способов настройки и выполнения запросов с помощью этого API с высоким состоянием , поэтому ваши модульные тесты быстро становятся неуправляемыми.

Есть несколько библиотек, которые помогут вам с тестированием базы данных. Просто назвать несколько:

  • MockRunner : у этого есть некоторые специфичные для JDBC расширения, которые позволяют имитировать JDBC ResultSets, а также проверять, выполняются ли реальные запросы
  • jMock : «обычная» библиотека- макет для Java
  • mockito : «обычная» библиотека для Java
  • DBUnit : Этот не издевается над вашей базой данных, он хорош для тестирования вашей базы данных. Еще один вариант использования, но все же стоит упомянуть здесь

Некоторые из перечисленных выше библиотек не помогут вам понять, что JDBC — это неуклюжий API для подделки, особенно если вам необходимо поддерживать несколько (несовместимых!) Версий JDBC одновременно. Некоторые примеры можно увидеть здесь:

Дразнить базу данных с помощью jOOQ

Когда вы используете jOOQ в своем приложении, в jOOQ 3.0 просто стало легко дразнить вашу базу данных. jOOQ теперь также поставляется с Mock JDBC Connection . Однако, в отличие от других платформ, вам нужно реализовать только один функциональный интерфейс с jOOQ и предоставить эту реализацию вашему MockConnection: MockDataProvider . Вот простой пример реализации:

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
30
31
MockDataProvider provider = new MockDataProvider() {
 
    // Your contract is to return execution results, given a context
    // object, which contains SQL statement(s), bind values, and some
    // other context values
    @Override
    public MockResult[] execute(MockExecuteContext context)
    throws SQLException {
 
        // Use ordinary jOOQ API to create an org.jooq.Result object.
        // You can also use ordinary jOOQ API to load CSV files or
        // other formats, here!
        Result<MyTableRecord> result = executor.newResult(MY_TABLE);
        result.add(executor.newRecord(MY_TABLE));
 
        // Now, return 1-many results, depending on whether this is
        // a batch/multi-result context
        return new MockResult[] {
            new MockResult(1, result)
        };
    }
};
 
// Put your provider into a MockConnection and use that connection
// in your application. In this case, with a jOOQ Executor:
Connection connection = new MockConnection(provider);
Executor create = new Executor(connection, dialect);
 
// Done! just use regular jOOQ API. It will return the values
// that you've specified in your MockDataProvider
assertEquals(1, create.selectOne().fetch().size());

Вышеуказанная реализация действует как обратный вызов для различных методов JDBC executeXXX (). С помощью очень простого API MockExecuteContext вы можете:

  • Получите доступ к выполненному SQL и значениям связывания (используйте общий jOOQ API, чтобы встроить значения связывания в оператор SQL)
  • Различают обычные операторы SQL и пакетные выполнения с одним оператором / несколькими связанными значениями и несколькими операторами / без обязательных значений
  • Вернуть один или несколько результатов, используя объекты jOOQ org.jooq.Result (которые можно легко импортировать из форматов CSV, XML, JSON, TEXT)
  • Возвращать «сгенерированные ключи» результаты через тот же API
  • Пусть MockStatement от jOOQ позаботится о сериализации ваших фиктивных данных через API JDBC

Существует также экспериментальная реализация MockFileDatabase , текстовой базы данных, которая использует следующий формат:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# This is a sample test database for MockFileDatabase
# Its syntax is inspired from H2's test script files
 
# When this query is executed...
select 'A' from dual;
# ... then, return the following result
> A
> -
> A
@ rows: 1
 
# Just list all possible query / result combinations
select 'A', 'B' from dual;
> A B
> - -
> A B
@ rows: 1
 
select 'TABLE1'.'ID1', 'TABLE1'.'NAME1' from 'TABLE1';
> ID1 NAME1
> --- -----
> 1   X
> 2   Y
@ rows: 2

MockFileDatabase реализует MockDataProvider, поэтому очень просто обеспечить ваши модульные тесты примерами данных. Будущие версии jOOQ позволят:

  • Операторы SQL для сопоставления с образцом Regex для получения фиктивных результатов
  • Загрузите эти результаты из других форматов, таких как поддерживаемые форматы экспорта jOOQ
  • Укажите поведение операторов пакетной обработки, операторов с несколькими результатами и т. Д.

Использование MockConnection от jOOQ в других контекстах

Здесь все не заканчивается. Поскольку MockConnection от jOOQ является точкой входа для этого поддельного API-интерфейса jOOQ, вы также можете использовать его в других средах, например, при выполнении запросов JPA, запросов Hibernate, iBatis или просто старых устаревших запросов JDBC.

JOOQ только что стал вашим любимым фреймворком JDBC!

Справка: Простое копирование вашей базы данных от нашего партнера по JCG Лукаса Эдера в блоге JAVA, SQL и JOOQ .