Как смоделировать БД для тестирования (Java)? - PullRequest
62 голосов
/ 30 мая 2009

Я программирую на Java, и мои приложения активно используют БД. Следовательно, для меня важно иметь возможность легко протестировать использование моей БД.
Что такое тесты БД? Для меня они должны предоставить два простых требования:

  1. Проверка синтаксиса SQL.
  2. Что еще более важно, проверьте, что данные выбраны / обновлены / вставлены правильно, в соответствии с данной ситуацией.

Что ж, похоже, все, что мне нужно, это БД.
Но на самом деле я предпочитаю нет, так как при тестировании БД существует несколько трудностей:

  • "Просто возьмите себе тестовую базу данных, насколько это может быть сложно?" - Ну, на моем рабочем месте, иметь личное тестирование БД довольно невозможно. Вы должны использовать «публичную» БД, доступную для всех.
  • «Эти тесты, конечно, не быстрые ...» - тесты БД, как правило, медленнее, чем обычные тесты. На самом деле не стоит проводить медленные тесты.
  • "Эта программа должна обрабатывать все случаи!" - Это становится несколько раздражающим и даже невозможным, чтобы попытаться смоделировать каждый случай в БД. Для каждого случая необходимо выполнить определенное количество запросов на вставку / обновление, что раздражает и занимает много времени.
  • "Подождите секунду, откуда вы знаете, что в этой таблице 542 строки?" - Один из основных принципов в тестировании - это возможность тестировать функциональность, отличную от функциональности вашего тестируемого кода. При использовании БД обычно есть один способ что-то сделать, поэтому тест в точности совпадает с кодом ядра.

Итак, вы можете понять, что мне не нравятся БД, когда дело доходит до тестов (конечно, мне придется в какой-то момент разобраться с этим, но я бы лучше попал туда позже, после того как обнаружил большинство ошибки, используя остальные методы испытаний). Но что я ищу?

Я ищу способ имитации БД, фиктивной БД, используя файловую систему или просто виртуальную память. Я подумал, что, возможно, есть инструмент / пакет Java, который позволяет просто создать (используя интерфейс кода) макет БД для каждого теста, с имитированными таблицами и строками, с проверкой SQL и с интерфейсом кода для мониторинга его состояния (а не с помощью SQL). ).

Вы знакомы с этим инструментом?


Редактировать: Спасибо за ответы! Хотя я и просил инструмент, вы также дали мне несколько советов по проблеме :) Мне потребуется некоторое время, чтобы проверить ваши предложения, поэтому я не могу сейчас сказать, были ли ваши ответы удовлетворительными.

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

public class TestDBMonitor extends TestCase {

    @Override
    public void setUp() throws Exception {

       MockConnection connection = new MockConnection();

       this.tableName = "table1";
       MockTable table = new MockTable(tableName);

       String columnName = "column1";
       ColumnType columnType = ColumnType.NUMBER;
       int columnSize = 50;
       MockColumn column = new MockColumn(columnName, columnType, columnSize);
       table.addColumn(column);

       for (int i = 0; i < 20; i++) {
           HashMap<MockColumn, Object> fields = new HashMap<MockColumn, Object>();
           fields.put(column, i);
           table.addRow(fields);
       }

       this.connection = connection;
    }

    @Test
    public void testGatherStatistics() throws Exception {

       DBMonitor monitor = new DBMonitor(connection);
       monitor.gatherStatistics();
       assertEquals(((MockConnection) connection).getNumberOfRows(tableName),
                    monitor.getNumberOfRows(tableName));
    }

    String tableName;
    Connection connection;
}

Надеюсь, этот код достаточно ясен, чтобы понять мою идею (извините за синтаксические ошибки, я печатал вручную без моего дорогого Eclipse: P).

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

Ответы [ 14 ]

1 голос
/ 30 мая 2009

Я согласен с banjollity. Настройка изолированных сред разработки и тестирования должна быть приоритетной задачей. Каждая система баз данных, которую я использовал, имеет либо открытый исходный код, либо имеет бесплатную версию для разработчиков, которую можно установить на локальную рабочую станцию. Это позволяет вам разрабатывать на том же диалекте базы данных, что и производственный, дает вам полный административный доступ к базам данных разработки и быстрее, чем при использовании удаленного сервера.

1 голос
/ 30 мая 2009

Мы создаем среду тестирования базы данных на работе прямо сейчас. Мы считаем, что должны использовать реальную систему управления базами данных с симулированными данными . Одна из проблем с имитируемой СУБД состоит в том, что SQL никогда не был полностью гелеобразным стандартом, поэтому искусственная среда тестирования должна была бы верно поддерживать диалект нашей производственной базы данных. Другая проблема заключается в том, что мы широко используем ограничения значений столбцов, ограничения внешнего ключа и ограничения уникальности, и, поскольку искусственный инструмент, вероятно, не реализует их, наши модульные тесты могут пройти, но наши системные тесты не пройдут, когда они впервые достигнут реального ограничения. Если тесты занимают слишком много времени, это указывает на ошибку реализации, и мы настраиваем наши запросы (обычно наборы тестовых данных незначительны по сравнению с производственными).

Мы установили настоящую СУБД на каждую машину разработчика и на наш сервер непрерывной интеграции и тестирования (мы используем Hudson). Я не знаю, каковы ваши ограничения рабочей политики, но довольно легко установить и использовать PostgreSQL, MySQL и Oracle XE. Все они бесплатны для разработки (даже Oracle XE), поэтому нет разумных оснований запрещать их использование.

Ключевой вопрос - как вы гарантируете, что ваши тесты всегда начинаются с базы данных в согласованном состоянии? Если бы тесты были только для чтения, никаких проблем. Если бы вы могли создать мутационные тесты, которые всегда выполняются в транзакциях, которые никогда не фиксируются, не проблема. Но, как правило, вам нужно беспокоиться об отмене обновлений. Для этого вы можете экспортировать исходное состояние в файл, а затем импортировать его обратно после тестирования (для этого используются команды Oracle exp и imp shell). Или вы можете использовать контрольно-пропускной пункт / откат. Но более элегантный способ - использовать такой инструмент, как dbunit , который хорошо работает для нас.

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

0 голосов
/ 10 апреля 2018

jOOQ - это инструмент, который помимо абстракции SQL также имеет встроенные небольшие инструменты, такие как SPI, который позволяет имитировать весь JDBC. Это может работать двумя способами, как описано в этом сообщении в блоге :

Реализуя MockDataProvider SPI:

// context contains the SQL string and bind variables, etc.
MockDataProvider provider = context -> {

    // This defines the update counts, result sets, etc.
    // depending on the context above.
    return new MockResult[] { ... }
};

В приведенной выше реализации вы можете программно перехватывать каждый оператор SQL и возвращать для него результат, даже динамически, "разбирая" строку SQL, чтобы извлечь некоторые предикаты / информацию таблицы и т. Д.

Используя более простой (но менее мощный) MockFileDatabase

... в следующем формате (набор пар оператор / результат):

select first_name, last_name from actor;
> first_name last_name
> ---------- ---------
> GINA       DEGENERES
> WALTER     TORN     
> MARY       KEITEL   
@ rows: 3

Приведенный выше файл можно затем прочитать и использовать следующим образом:

import static java.lang.System.out;
import java.sql.*;
import org.jooq.tools.jdbc.*;

public class Mocking {
    public static void main(String[] args) throws Exception {
        MockDataProvider db = new MockFileDatabase(
            Mocking.class.getResourceAsStream("/mocking.txt");

        try (Connection c = new MockConnection(db));
            Statement s = c.createStatement()) {

            out.println("Actors:");
            out.println("-------");
            try (ResultSet rs = s.executeQuery(
                "select first_name, last_name from actor")) {
                while (rs.next())
                    out.println(rs.getString(1) 
                        + " " + rs.getString(2));
            }
        }
    }
}

Обратите внимание, как мы используем API JDBC напрямую, без фактического подключения к какой-либо базе данных.

Обратите внимание, я работаю на поставщика jOOQ, поэтому этот ответ предвзят.

Осторожно, в какой-то момент вы реализуете целую базу данных

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

  1. Проверка синтаксиса SQL.

ОК, смоделировав базу данных, как показано выше, вы можете «проверить» синтаксис, потому что любой синтаксис, который вы не предусмотрели в точной версии, как указано выше, будет отвергнут при любом таком подходе. .

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

  1. Что еще более важно, убедитесь, что данные выбраны / обновлены / вставлены правильно, в соответствии с данной ситуацией.

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

Как убедиться, что это происходит при "издевательстве" над базой данных? Вам нужен конечный автомат, который запоминает состояние каждой «ложной» таблицы. Другими словами, вы создадите базу данных.

Насмешка приведет вас так далеко

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

0 голосов
/ 30 мая 2009

Ну, для начала, вы используете какой-либо уровень ORM для доступа к БД?
Если нет: то, что вы думаете, будет бесполезно. Какой смысл использовать тестирование, когда вы не уверены, что SQL, который вы запускаете, будет работать с вашей БД в работе, как в тестовых случаях, когда вы используете что-то другое.
Если да: то вы можете посмотреть на различные варианты, указанные.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...