Як створити масштабні та побічні тести на безкоштовну інтеграцію?


14

У моєму поточному проекті мені важко придумати хороше рішення для створення масштабованих тестів на інтеграцію, які не мають побічних ефектів. Невелике уточнення щодо побічних властивостей вільної дії: йдеться переважно про базу даних; після завершення тестів не повинно бути ніяких змін у базі даних (стан повинен зберігатися). Можливо, масштабність та збереження держави не поєднуються, але мені дуже хочеться наполягати на кращому рішенні.

Ось типовий тест на інтеграцію (ці тести стосуються шару бази даних):

public class OrderTests {

    List<Order> ordersToDelete = new ArrayList<Order>(); 

    public testOrderCreation() {
        Order order = new Order();
        assertTrue(order.save());
        orderToDelete.add(order);
    }

    public testOrderComparison() {
        Order order = new Order();
        Order order2 = new Order();
        assertFalse(order.isEqual(order2);
        orderToDelete.add(order);
        orderToDelete.add(order2);
    }
    // More tests

    public teardown() {
         for(Order order : ordersToDelete)
             order.delete();
    }
}

Як можна уявити, такий підхід дає надзвичайно повільні тести. І, застосовуючи до цілих інтеграційних тестів, потрібно лише 5 секунд, щоб протестувати лише невелику частину системи. Я можу уявити, що ця кількість зростає, коли покриття збільшується.

Який би був ще один підхід до написання таких тестів? Я можу подумати про те, що є різновиди глобальних змінних (у класі), і всі методи тестування мають цю змінну. В результаті створюються та видаляються лише кілька замовлень; що призводить до більш швидких тестів. Однак я вважаю, що це створює більшу проблему; тести вже не поодинокі, і їх стає важче зрозуміти та проаналізувати.

Можливо, просто те, що тести інтеграції не запускаються так часто, як одиничні тести; тому низька продуктивність може бути прийнятною для них. У будь-якому випадку, було б чудово знати, чи хтось придумав альтернативи для покращення масштабованості.

Відповіді:


6

Погляньте на використання Hypersonic або іншої БД пам'яті для тестування одиниць. Тести не тільки виконуватимуться швидше, але й побічні ефекти не мають значення. (Відкат транзакцій після кожного тесту також дає змогу запускати багато тестів в одному і тому ж екземплярі)

Це також змусить вас створити макети даних, що добре, IMO, оскільки це означає, що те, що відбувається у виробничій базі даних, не може незрозуміло почати провал ваших тестів. "Це могло б виглядати, що допомагає, якщо вам потрібно раптом розгорнути новий екземпляр програми без зв'язку з існуючим виробничим сайтом.

Так, я сам використовую цей метод, і так, це було ПДТА, щоб створити ПЕРШИЙ час, але це більше, ніж заплатили за себе протягом життя проекту, який я збираюся завершити. Існує також ряд інструментів, які допомагають у макеті даних.


Звучить чудова ідея. Особливо мені подобається його повна ізоляція; починаючи з нової установки бази даних. Здається, що це зажадає певних зусиль, але після встановлення це буде дуже вигідно. Спасибі.
Гувен

3

Це вічна проблема, з якою стикаються всі під час написання інтеграційних тестів.

Ідеальним рішенням, особливо, якщо ви тестуєте виробництво, є відкриття транзакції з налаштуванням та повернення її назад у скрін. Я думаю, що це повинно відповідати вашим потребам.

Якщо це неможливо, наприклад, коли ви тестуєте додаток на рівні клієнта, іншим рішенням є використання БД на віртуальній машині та зйомка в налаштуванні та повернення до неї в скріншоті (він не займайте стільки, скільки ви могли очікувати).


Не можу повірити, що не думав про відкат транзакцій. Я буду використовувати цю ідею як швидке виправлення рішення, але в кінцевому підсумку БД в пам'яті звучить дуже перспективно.
Гувен

3

Інтеграційні тести завжди повинні проводитись у відповідності з виробничою структурою. У вашому випадку це означає, що ви повинні мати ту саму базу даних та сервер додатків. Звичайно, заради продуктивності ви могли вирішити використовувати БД в пам'яті.

Що ви ніколи не повинні робити, це розширити сферу вашої транзакції. Деякі люди пропонували взяти на себе контроль над транзакцією та повернути її назад після тестів. Коли ви це зробите, всі об'єкти (якщо припустити, що ви використовуєте JPA) залишатимуться прив’язаними до контексту постійності протягом усього виконання тесту. Це може призвести до дуже неприємних помилок, які дуже важко знайти .

Натомість слід очистити базу даних вручну після кожного тесту через бібліотеку типу JPAUnit або подібний до цього підходу (очистити всі таблиці за допомогою JDBC).

Що стосується проблем із продуктивністю, ви не повинні виконувати тести інтеграції для кожної збірки. Нехай ваш сервер безперервної інтеграції робить це. Якщо ви використовуєте Maven, ви можете насолоджуватися безвідмовне плагін, який дозволяє відокремити тести на одиничні і інтеграційні тести.

Також не слід нічого знущатися. Пам'ятайте, що ви інтегруєте тестування, тобто тестування поведінки в середовищі виконання часу виконання.


Гарна відповідь. Один момент: може бути прийнятним глузування з деяких зовнішніх залежностей (наприклад, надсилання електронної пошти). Але ви, швидше, знущаєтесь, налаштовуючи повний сервіс-макет / сервер, а не знущайтесь над ним у коді Java.
sleske

Sleske, я з вами згоден. Особливо, коли ви використовуєте JPA, EJB, JMS або впроваджуєте іншу специфікацію. Ви можете поміняти обмін сервером додатків, сервером додатків або базою даних. Наприклад, ви можете скористатися вбудованими Glassfish та HSQLDB для простої настройки та підвищення швидкості (ви, звичайно, можете вибрати іншу сертифіковану реалізацію).
БенР

2

На масштабованість

У мене виникала ця проблема раніше, тому що тести на інтеграцію зайняли занадто довго, і не було практичним для одного розробника, щоб постійно працювати в тісному циклі зворотного зв'язку. Деякі стратегії впоратися з цим є:

  • Напишіть менше інтеграційних тестів - якщо ви добре покриваєтесь тестовими модулями в системі, тести інтеграції повинні бути більш зосереджені на (ах) питаннях інтеграції, на тому, як різні компоненти працюють разом. Вони більше схожі на тести на дим, які просто намагаються перевірити, чи працює система в цілому. Тож в ідеалі тести вашого блоку охоплюють більшість функціональних частин програми, а тести інтеграції просто перевіряють взаємодію цих частин між собою. Тут не потрібно широкого висвітлення логічних шляхів, а лише деякі критичні шляхи через систему.
  • Запускайте лише підмножину тестів за раз - як окремий розробник, який працює над деякими функціональними можливостями, у вас зазвичай виникає відчуття, які тести необхідні для покриття цієї функціональності. Запускайте лише ті тести, які мають сенс висвітлити ваші зміни. Такі рамки, як JUnit, дозволяють групувати світильники в категорії . Створіть групування, які дозволять найкраще охопити кожну функцію. Звичайно, ви все ще хочете запустити всі тести інтеграції в якийсь момент, можливо, перед тим, як звернутися до системи управління джерелом і, звичайно, на сервер безперервної інтеграції.
  • Оптимізація системи - Інтеграційні тести у поєднанні з деякими тестами на ефективність можуть дати вам необхідний вклад для налаштування повільних частин системи, так що тести будуть працювати швидше пізніше. Це може допомогти виявити необхідні індекси в базі даних, чат-інтерфейси між підсистемами або інші вузькі місця, які потребують адреси.
  • Виконайте тести паралельно. Якщо у вас є хороша група ортогональних тестів, ви можете спробувати запустити їх паралельно . Будьте уважні до ортогональної вимоги, про яку я згадував, але ви не хочете, щоб ваші тести ступали в ноги.

Спробуйте комбінувати ці методи для отримання більшого ефекту.


1
Дійсно хороші вказівки; написання меншої кількості інтеграційних тестів - це точно найкраща порада. Також паралельне їх виконання було б дуже хорошою альтернативою; ідеальний "тест", щоб перевірити, чи я отримав свої тести прямо в плані ізоляції.
Ґувен

2

Для тестування ми використовували розгортання на базі файлів бази даних SQLite (просто скопіюйте ресурс). Це було зроблено, щоб ми також могли перевірити міграцію схем. Наскільки мені відомо, зміни схеми не є транзакційними, тому їх не буде відмовлено після завершення транзакції. Крім того, не потрібно покладатися на підтримку транзакцій для встановлення тесту, дозволяє перевірити поведінку транзакцій із вашої програми.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.