Очистка базы данных после тестов Junit
Я должен проверить некоторые бережливые услуги с помощью Junit. Когда я запускаю свои тесты как бережливый клиент, службы изменяют базу данных сервера. Я не могу найти хорошее решение, которое можно очистить базу данных после каждого теста. Очистка важна, особенно потому, что идентификаторы должны быть уникальными, которые в настоящее время читаются из XML-файла. Теперь я должен вручную изменить идентификаторы после запуска тестов, чтобы следующий набор тестов мог работать без нарушения первичного ключа в базе данных. Если я могу очистить базу данных после каждого тестового запуска, то проблема полностью решена, иначе мне придется думать о других решениях, таких как генерация случайных идентификаторов и использование их везде, где требуются идентификаторы.
Edit: я хотел бы подчеркнуть, что я тестирую службу, которая пишет в базу данных, у меня нет прямого доступа к базе данных. Но поскольку служба наша, я могу изменить службу, чтобы предоставить любой метод очистки, если это необходимо.
9 ответов
Если вы не тестируете определенные действия базы данных (например, можете запросить или обновить базу данных), Ваши 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);
}
Если вы используете Spring, все, что вам нужно, это аннотация @DirtiesContext в вашем тестовом классе.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/test-context.xml")
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public class MyServiceTest {
....
}
структура модульного тестирования Spring имеет широкие возможности для работы с JDBC. Общий подход заключается в том, что модульные тесты выполняются в транзакции, и (вне теста) транзакция откатывается после завершения теста.
Это имеет то преимущество, что вы можете использовать свою базу данных и ее схему, но без каких-либо прямых изменений данных. Конечно, если вы действительно выполняете фиксацию внутри своего теста, то все ставки отменяются!
дополнительные читать, ищите документация Spring об интеграционном тестировании с JDBC.
при написании тестов 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
Если у вас есть доступ к базе данных: другой вариант-создать резервную копию базы данных перед тесты и восстановить из резервной копии, что после испытаний. Это можно автоматизировать.
Если вы используете Spring + Junit 4.x тогда вам не нужно ничего вставлять в DB. Смотреть AbstractTransactionalJUnit4Springcontexttests класса.
также ознакомьтесь с документацией Spring для поддержки JUnit.
Это немного драконовски, но я обычно стремлюсь стереть базу данных (или только таблицы, которые меня интересуют) перед каждым выполнением метода тестирования. Конечно, это не работает, поскольку я перехожу к более интеграционным тестам.
в случаях, когда у меня нет контроля над базой данных, скажем, я хочу проверить правильное количество строк, созданных после данного вызова, тогда тест будет подсчитывать количество строк до и после тестируемого вызова и убедитесь, что разница правильный. Другими словами, принять во внимание существующие данные, а затем посмотреть, как тестируемый код изменил вещи, ничего не предполагая о существующих данных. Это может быть немного работы для настройки, но давайте я протестирую против более "живой" системы.
в вашем случае важны ли конкретные идентификаторы? Не могли бы вы генерировать идентификаторы на лету, возможно, случайным образом, проверить, что они еще не используются, а затем продолжить?
Я согласен с Brainimus, если вы пытаетесь проверить данные, которые вы вытащили из базы данных. Если вы хотите протестировать изменения, внесенные в базу данных, другим решением будет макет самой базы данных. Существует несколько реализаций баз данных в памяти, которые можно использовать для создания временной базы данных (например, во время JUnit setUp()
), а затем удалите всю базу данных из памяти (во время tearDown()
). Пока вы не используете SQL для конкретного поставщика, Это хороший способ проверить изменение базы данных, не касаясь вашего реального производства.
некоторые хорошие базы данных Java, которые предлагают поддержку памяти, являются Apache Дерби, JAVA DB (но это действительно вкус Oracle Apache Derby снова),базы данных hypersql (более известный как HSQLDB) и H2 Database Engine. Я лично использовал HSQLDB для создания в памяти макетных баз данных для тестирования, и он отлично работал, но я уверен, что другие предложат такой же результат.