Як я можу перевірити клас, який вимагає виклику веб-служби?


21

Я намагаюся перевірити клас, який викликає деякі веб-сервіси Hadoop. Форма коду в значній мірі:

method() {
    ...use Jersey client to create WebResource...
    ...make request...
    ...do something with response...
}

наприклад, існує метод створення каталогу, метод створення папки тощо.

Зважаючи на те, що код має справу із зовнішньою веб-службою, над якою я не маю контролю, як я можу це перевірити? Я міг би спробувати знущатися з клієнта / відповідей веб-сервісу, але це порушує правила, які я бачив останнім часом: "Не знущайтеся над об'єктами, якими ви не володієте". Я можу створити фіктивну реалізацію веб-сервісу - чи все-таки це "тест на одиницю" чи це був би тест на інтеграцію? Чи просто неможливо провести тестування на такому низькому рівні - як би з цим справився практик TDD?


5
Де ви бачили рекомендації щодо того, щоб не знущатися над речами, якими ви не володієте? Це здається величезною причиною, чому слід знущатися над речами ...
Томас Оуенс

1
Я читав це у багатьох блогах, один з яких посилається на amazon.com/Growing-Object-Oriented-Software-Guided-Tests/dp/…, що, на мою думку, є добре оціненою книгою ( blog.8thlight. com / eric-smith / 2011/10/27 / thats-not-tvoje.html , mockobjects.com/2007/04/test-smell-everything-is-mocked.html )
Кріс Купер

1
@ChrisCooper: Чи можу зазначити, що остання посилання дуже застаріла (з 2007 року). Багато часу змінилося. Я отримую відчуття від поста, що глузувати було набагато складніше тоді, коли вам довелося реально реалізувати поведінку, а не просто використовувати глузливі рамки або метапрограмування для встановлення повернених значень ...
c_maker

Відповіді:


41

На мою думку, ви повинні знущатися над дзвінками веб-сервісів, якщо це тест на одиницю, на відміну від тесту на інтеграцію.

Тест вашого пристрою не повинен перевіряти, чи працює зовнішня веб-служба, чи правильна ваша інтеграція з нею. Не надто догматично ставившись до TDD, зауважте, що побічним ефектом перетворення вашого тесту на пристрій в інтеграційний тест є те, що він, швидше за все, працює повільніше, і вам потрібно швидкі тестові одиниці.

Крім того, якщо веб-служба тимчасово не працює або працює неправильно, чи це може спричинити збій вашого тесту приладу? Це не здається правильним. Ваш тест одиниці повинен пройти лише з однієї причини: якщо в коді в цьому "блоці" є помилка.

Єдина частина коду, яка тут є актуальною, - це ...do something with response.... Знущаються над рештою.


2
Пам'ятайте, що вам доведеться тримати значення підпису об'єкта і повертати значення синхронно з тими, що генеруються веб-сервісом Hadoop протягом усіх неминучих змін у цій службі.
pcurry

Рідко варто тестувати нестандартні компоненти, такі як Hadoop. Але якщо ви зателефонували на користувальницьку веб-службу, яку надає інша команда чи організація, ви, можливо, захочете написати тест на це у захисті. Таким чином, коли все піде не так, ви можете швидко перевірити, чи проблема полягає у вашому коді чи веб-службі. Це не тестовий пристрій, який повинен запускатися автоматично; це діагностика для запуску за потребою.
Кевін Клайн

@kevincline я повністю погоджуюся з необхідністю запропонованих вами тестів, і я справді пишу їх у своїй щоденній роботі і виявили себе корисними. Але вони за визначенням НЕ одиничні тести, до чого йшлося питання :) Поміркуйте: якщо це тест одиниці, а код не вдається, оскільки веб-сервіс був змінений, що таке "одиниця", яку ви тестуєте? Що саме не вдалося? Ви не проводить тестування поодиноко, як це потрібно для одиничного тестування.
Андрес Ф.

1
@AndresF. Я думаю, що ми дотримуємось жорстокої згоди: "Цей [діагностичний] НЕ є одиничним тестом ..."
Кевін Клайн

@kevincline Правильно! Я неправильно прочитав ваш коментар, вибачте!
Андрес Ф.

5

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

Смішні цілі існування - це те, що будуть модулі, бібліотеки, класи, якими ми не володітимемо.

Моя пропозиція щодо вашого сценарію - глузування з дзвінка веб-служби.

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

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


1

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

class WebClass {

private WebServiceInterface webserviceInterface;

    void method(){
        R result = webServiceInterface.performWebServiceCall();
        ... do something with result
    }

    public void setWebServiceInterface(WebServiceInterface webServiceInterface){
        this.webServiceInterface = webServiceInterface;
    }
}


interface WebServiceInterface {

   R performWebServiceCall();

}


class WebClassTest {

private WebServiceInterface mock;    
private R sampleResult = new R();

    @Before
    public void before(){
        mock = EasyMock.createMock(WebServiceInterface.class);
    }


    @Test
    public void test() {
        WebClass classUnderTest = new WebClass();
        EasyMock.expect(mock.performWebServiceCall()).andReturn(sampleResult);
        classUnderTest.setWebServiceInterface(mock);
        classUnderTest.method();
        EasyMock.verify(mock);
    }
}

Перше, що вам потрібно зробити, - це витягнути логіку у своєму класі, де ви використовуєте Джерсі, щоб отримати WebResource та викликати веб-службу в окремий клас. Створення інтерфейсу для цього класу дозволить вам створити макет, якому ви зможете потім диктувати поведінку.

Після створення цього інтерфейсу ви можете створити макет за допомогою EasyMock, який поверне вказаний об'єкт відповідно до вашого тестового випадку. Наведений вище приклад - це спрощення того, як структурувати базовий глузливий тест і як працюватиме ваш інтерфейс.

Для отримання додаткової інформації про знущання з фреймворків див. Це питання . Також цей приклад передбачає використання Java, але глузуючі рамки доступні на всіх мовах, і хоча вони реалізовані по-різному, вони працюватимуть загалом однаково


1

Знущання в цьому випадку прийнятні, але вам це не потрібно. Замість одиничного тестування method()замість одиниці тестуйте лише ту частину, яка обробляє відповідь.

Витягніть функцію, яка займає ResponseData(будь-який тип підходить), а потім виконує дію.

Замість того, щоб глузувати, тепер ви просто побудуєте об’єкт ResponseData і передасте його.

Ви можете залишити виклик служби на повні інтеграційні тести - що охоплюватимуть method()загалом


0

Що я зробив, і це працює:

  1. Запропонувати всі веб-сервіси кодового дзвінка через проксі.
  2. Проксі викликає клас, який статично знає, використовуємо ми проксі чи ні, і перенаправляє відповідно. Знущання - це лише HashMaps, які на кожен запит повертають задану відповідь.
  3. Виконайте тести кілька разів у такому порядку:

3.1 Спочатку всі веб-сервіси тестуються. З кожної машини навіть машини розробника. Це справжні веб-сервіси, але вони працюють у навколишньому середовищі розвитку. Це означає, що веб-сервіси ніколи не можуть вмикати або відповідати помилковими значеннями, оскільки в іншому випадку кожен розробник скаржиться на те, що він не може компілювати.

3.2. Після цього проводяться всі тести одиниці, що працюють у програмі. Це означає, що всі веб-сервіси знущаються та перевіряються, виконуючи ті ж тести, що й 3.1 (і вони також повинні пройти, інакше макети неправильні), і викликується реальною програмою так, ніби вони справді використовуються. Якщо макети неправильні, ви можете запустити тест у 3.1 та записати ці (запит, відповідь) значення у HashMap.

3.3 Потім виконуються ті ж тести, що й 3.2, але цього разу проти реальних веб-сервісів, що працюють у середовищі розробки.

Після того, як все це буде завершено, для реального виробничого середовища потрібно просто вказати реальну адресу для кожної веб-служби. Сподіваємось, це не потребує занадто великих змін у конфігурації.

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