#java #postgresql #jdbc #junit #automated-tests
#java #postgresql #jdbc #junit #автоматизированные тесты
Вопрос:
Я пытаюсь написать модульный тест для одного из методов доступа к базе данных нашего приложения. У нас есть выделенная тестовая база данных (периодический дамп / копия текущей базы данных). Обычно каждый тестовый пример выполняется в одной транзакции, а затем откатывается. Мы достигаем этого, используя Connection.setAutoCommit(false)
перед тестовым примером и Connection.rollback()
после.
Но на этот раз я пытаюсь написать тест для метода, который сам выполняет все как одну транзакцию и использует Connection.commit()
в конце.
Есть ли способ, которым я могу commit
предотвратить фактическую фиксацию в базе данных, не выдавая ошибку в тестируемом методе? То есть, как я могу предотвратить реальное изменение содержимого тестовой базы данных в этом тестовом примере?
Примечания: использование Java, JDBC и Junit. java.sql.Connection
используется для подключений к базе данных и java.sql.PreparedStatement
используется для выполнения запросов.
Код @Before и @After:
/**
* Obtain a new connection and set autoCommit to false.
* This lets us run a test case then revert all of the changes
* so the test cases don't interfere with each other.
*/
@Before
public void initConnection() {
conn = Database.getConnection();
try {
conn.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
fail("Unable to set connection AutoCommit=false");
}
}
/**
* Rollback the changes made by the test case
* and close the connection.
*/
@After
public void rollbackConnection() {
try {
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
fail("Unable to rollback");
}
Database.closeConnection(conn);
}
Ответ №1:
Почему вы хотите это сделать? Если вы пишете правильный тест, вы, вероятно, захотите убедиться, что данные действительно были зафиксированы и соответствуют тому, чего вы пытаетесь достичь. Если вы беспокоитесь об изменениях, уберите их, когда закончите.
Однако, если действительно есть веская причина, вы можете удалить код транзакции (txn), написать вспомогательную функцию, которая оборачивает вызов функции в транзакцию, и клиенты вызывают эту вспомогательную функцию, а тестовый код вызывает оригинал. Вероятно, это не лучший способ сделать это, но вариант.
Комментарии:
1. Вам не нужно фиксировать, чтобы протестировать и подтвердить изменения, вам просто нужно использовать одно и то же соединение для любого кода загрузки, используемого для подтверждения изменений, до отката.
2. @MartinCarney — Тогда тест на самом деле проверяет не базу данных, а только логику кода в изоляции. Если у вас есть тестовая база данных, нет причин, по которым вы не должны выполнять фиксацию, и вы сталкиваетесь с проблемами, подобными этой, когда ваш код должен быть адаптирован к тестовому сценарию, а не наоборот. Просто используйте базу данных в памяти или набор макетов, если вы просто хотите протестировать логику, но вы открываете себя для проверки в будущем.
Ответ №2:
Спросил моих коллег по офису, есть ли у них какие-либо идеи. Один предложил издеваться над ним (используя Mockquito), что привело меня к немного лучшей альтернативе. Я создаю оболочку для Connection
этого расширения Connection
и действует как обычное соединение, но когда используются его методы, связанные с транзакциями, он ведет себя по-другому.
В продакшене Connection
используется обычный, а для тестовых примеров будет использоваться этот класс-оболочка.
В частности:
- Он запускает реальную транзакцию, когда она создается в начале каждого тестового примера.
- Когда ему говорят установить для автоматической фиксации значение false (обычно так мы запускаем длинную транзакцию), он создает
Savepoint
и удерживает его - Когда ему говорят зафиксировать, он освобождает старый
Savepoint
и получает новый. - Когда ему говорят откат, он возвращается к
Savepoint
. - Установка значения autocommit в true, когда для него было установлено значение false, освобождает
Savepoint
. - Если ему указано установить a
Savepoint
(который должен запускать транзакцию, если она не выполняется), он запускает поддельную транзакцию, как указано выше, в дополнение к настройке запрошенногоSavepoint
. - В конце тестового примера выполняется откат реальной транзакции.
Эти изменения позволяют ему действовать так, как будто он находится в транзакции для методов, которые он тестирует, которые используют транзакции, сохраняя при этом возможность возврата всего после завершения тестового примера.
PS — Если есть что-то, что я должен делать, но не делаю, дайте мне знать, чтобы я мог улучшить класс-оболочку.