Очистка базы данных после тестов Junit - PullRequest
12 голосов
/ 05 августа 2010

Я должен протестировать некоторые сервисы Thrift, используя Junit. Когда я запускаю свои тесты в качестве клиента Thrift, сервисы изменяют базу данных сервера. Я не могу найти хорошее решение, которое может очистить базу данных после каждого теста. Очистка важна особенно потому, что идентификаторы должны быть уникальными, которые в настоящее время считываются из файла XML. Теперь я должен вручную изменить идентификаторы после запуска тестов, чтобы следующий набор тестов мог выполняться без выброса нарушения первичного ключа в базу данных. Если я смогу очистить базу данных после каждого запуска теста, тогда проблема будет полностью решена, иначе мне придется подумать о других решениях, таких как генерация случайных идентификаторов и их использование везде, где требуются идентификаторы.

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

Ответы [ 9 ]

15 голосов
/ 27 июня 2013

Если вы используете Spring, все, что вам нужно, это аннотация @DirtiesContext в вашем тестовом классе.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/test-context.xml")
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public class MyServiceTest {
   ....
}
7 голосов
/ 05 августа 2010

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

Вы можете издеваться над вашими классами несколькими способами. Вы можете использовать библиотеку, такую ​​как JMock , которая сделает всю работу по выполнению и проверке за вас. Мой личный любимый способ сделать это с помощью Dependency Injection. Таким образом я могу создавать фиктивные классы, которые реализуют мои интерфейсы репозитория (вы используете интерфейсы для своего уровня доступа к данным, верно? ;-)), и я реализую только необходимые методы с известными действиями / возвращаемыми значениями.

//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);
}
5 голосов
/ 06 августа 2010

Как насчет использования чего-то вроде DBUnit ?

4 голосов
/ 05 августа 2010

При написании тестов 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
4 голосов
/ 05 августа 2010

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

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

Подробнее читайте в документации Spring по интеграционному тестированию с JDBC.

2 голосов
/ 05 августа 2010

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

1 голос
/ 06 августа 2010

Я согласен с Brainimus, если вы пытаетесь проверить данные, которые вы извлекли из базы данных. Если вы хотите протестировать изменения, внесенные в базу данных, другим решением будет макетирование самой базы данных. Существует несколько реализаций баз данных в памяти, которые вы можете использовать для создания временной базы данных (например, во время JUnit setUp()), а затем для удаления всей базы данных из памяти (во время tearDown()). Пока вы не используете специфичный для поставщика SQL, это хороший способ протестировать изменение базы данных, не затрагивая вашу реальную производственную.

Некоторые хорошие базы данных Java, которые предлагают поддержку памяти: Apache Derby , Java DB (но на самом деле это опять-таки разновидность Oracle в Apache Derby), HyperSQL (более известный как HSQLDB) и H2 Database Engine . Я лично использовал HSQLDB для создания фиктивных баз данных в памяти для тестирования, и он отлично работал, но я уверен, что другие предложат аналогичные результаты.

1 голос
/ 05 августа 2010

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

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

В вашем случае важны конкретные идентификаторы? Не могли бы вы сгенерировать идентификаторы на лету, возможно, случайно, проверить, что они еще не используются, а затем продолжить?

1 голос
/ 05 августа 2010

Если вы используете Spring + Junit 4.x, вам не нужно ничего вставлять в БД. смотреть на AbstractTransactionalJUnit4SpringContextTests класс.

Также ознакомьтесь с документацией Spring для поддержки JUnit.

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