Очистка базы данных после тестов Junit
Мне нужно проверить некоторые услуги Thrift с помощью Junit. Когда я запускаю свои тесты в качестве Thrift-клиента, службы изменяют базу данных сервера. Я не могу найти хорошее решение, которое может очистить базу данных после запуска каждого теста.
Очистка важна, особенно потому, что идентификаторы должны быть уникальными, которые в настоящее время считываются из XML файла. Теперь я должен вручную изменить идентификаторы после запуска тестов, чтобы следующий набор тестов мог работать без нарушения первичного ключа в базе данных. Если я могу очистить базу данных после каждого тестового прогона, тогда проблема полностью решена, иначе мне придется подумать о других решениях, таких как генерация случайных идентификаторов и их использовании везде, где требуется идентификатор.
Изменить: я хотел бы подчеркнуть, что я тестирую службу, которая пишет в базу данных, у меня нет прямого доступа к базе данных. Но поскольку сервис является нашим, я могу изменить службу, чтобы обеспечить какой-либо метод очистки, если это необходимо.
Ответы
Ответ 1
Если вы не тестируете конкретные действия с базой данных (например, вы можете запросить или обновить базу данных), ваши JUnits не должны записываться в настоящую базу данных. Вместо этого вы должны издеваться над классами базы данных. Таким образом, вам фактически не нужно подключать и изменять базу данных, и поэтому очистка не требуется.
Вы можете высмеивать свои классы несколькими способами. Вы можете использовать библиотеку, такую как JMock, которая будет выполнять всю работу по выполнению и проверке. Мой личный любимый способ сделать это - это инъекция зависимостей. Таким образом, я могу создавать макетные классы, которые реализуют мои интерфейсы репозитория (вы используете интерфейсы для своего уровня доступа к данным правильно?;-)), и я реализую только необходимые методы с известными действиями/возвращаемыми значениями.
//Example repository interface.
public interface StudentRepository
{
public List<Student> getAllStudents();
}
//Example mock database class.
public class MockStudentRepository implements StudentRepository
{
//This method creates fake but known data.
public List<Student> getAllStudents()
{
List<Student> studentList = new ArrayList<Student>();
studentList.add(new Student(...));
studentList.add(new Student(...));
studentList.add(new Student(...));
return studentList;
}
}
//Example method to test.
public int computeAverageAge(StudentRepository aRepository)
{
List<Student> students = aRepository.GetAllStudents();
int totalAge = 0;
for(Student student : students)
{
totalAge += student.getAge();
}
return totalAge/students.size();
}
//Example test method.
public void testComputeAverageAge()
{
int expectedAverage = 25; //What the expected answer of your result set is
int actualAverage = computeAverageAge(new MockStudentRepository());
AssertEquals(expectedAverage, actualAverage);
}
Ответ 2
Если вы используете Spring, все, что вам нужно, это аннотация @DirtiesContext в вашем тестовом классе.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/test-context.xml")
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public class MyServiceTest {
....
}
Ответ 3
Как насчет того, чтобы использовать что-то вроде DBUnit?
Ответ 4
Spring модульная система тестирования имеет обширные возможности для работы с JDBC. Общий подход заключается в том, что единичные тесты выполняются в транзакции, и (за пределами вашего теста) транзакция откатывается после завершения теста.
Это имеет то преимущество, что вы можете использовать свою базу данных и ее схему, но не внося никаких прямых изменений в данные. Конечно, если вы на самом деле выполняете фиксацию внутри своего теста, тогда все ставки отключены!
Подробнее читайте в Spring документации по тестированию интеграции с JDBC.
Ответ 5
При написании тестов JUnit вы можете переопределить два конкретных метода: setUp() и tearDown(). В setUp() вы можете установить все необходимое, чтобы протестировать ваш код, чтобы вам не приходилось устанавливать настройки в каждом конкретном тестовом случае. tearDown() вызывается после запуска всех тестовых случаев.
Если возможно, вы можете настроить его, чтобы открыть базу данных в методе setUp(), а затем очистить все от тестов и закрыть его в методе tearDown(). Так мы прошли все тесты, когда у нас есть база данных.
Вот пример:
@Override
protected void setUp() throws Exception {
super.setUp();
db = new WolfToursDbAdapter(mContext);
db.open();
//Set up other required state and data
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
db.dropTables();
db.close();
db = null;
}
//Methods to run all the tests
Ответ 6
Предполагая, что у вас есть доступ к базе данных: Еще один вариант - создать резервную копию базы данных непосредственно перед тестированием и восстановить ее после тестирования. Это может быть автоматизировано.
Ответ 7
Если вы используете Spring + Junit 4.x, вам не нужно вставлять что-либо в БД.
смотреть на
AbstractTransactionalJUnit4SpringContextTests класс.
Также ознакомьтесь с документацией Spring для поддержки JUnit.
Ответ 8
Это немного драконов, но я обычно стараюсь уничтожить базу данных (или только те таблицы, которые меня интересуют) перед каждым исполнением тестового метода. Это, как правило, не работает, поскольку я, конечно же, перехожу в тестеры с интеграционным типом.
В тех случаях, когда я не контролирую базу данных, скажу, что я хочу проверить правильное количество строк, созданных после данного вызова, тогда тест будет подсчитывать количество строк до и после тестируемого вызова и убедиться, что разница правильная. Другими словами, учтите существующие данные, а затем посмотрите, как проверенный код изменил ситуацию, не предполагая ничего о существующих данных. Это может быть небольшая работа по настройке, но позвольте мне протестировать более "живую" систему.
В вашем случае важны ли конкретные идентификаторы? Могли бы вы генерировать идентификаторы "на лету", возможно, случайно, проверить, что они еще не используются, а затем продолжить?
Ответ 9
Я согласен с Brainimus, если вы пытаетесь протестировать данные, которые вы вытащили из базы данных. Если вы хотите проверить изменения, внесенные в базу данных, другим решением будет издеваться над самой базой данных. Существует несколько реализаций баз данных в памяти, которые можно использовать для создания временной базы данных (например, во время JUnit setUp()
), а затем удалить всю базу данных из памяти (в течение tearDown()
). До тех пор, пока вы не используете SQL-специфический поставщик, это хороший способ проверить изменение базы данных, не касаясь вашего реального производственного.
Некоторые хорошие базы данных Java, которые предлагают поддержку в памяти, Apache Derby, Java DB (но это действительно дух Oracle Apache Derby), HyperSQL (более известный как HSQLDB) и H2 Database Engine. Я лично использовал HSQLDB для создания in-memory mock баз данных для тестирования, и он отлично работал, но я уверен, что другие предложили бы похожие результаты.