Очистка базы данных после тестов 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 баз данных для тестирования, и он отлично работал, но я уверен, что другие предложили бы похожие результаты.