Чи є сенс вимірювати умовне покриття коду Java 8?


19

Мені цікаво, чи вимірювання покриття умовного коду поточними інструментами для Java не застаріло з моменту появи Java 8. Завдяки Java 8 Optionalі Streamми часто можемо уникати гілок / циклів коду, що дозволяє легко отримати дуже високе умовне покриття без тестування всіх можливих шляхів виконання. Порівняємо старий код Java з кодом Java 8:

Перед Java 8:

public String getName(User user) {
    if (user != null) {
        if (user.getName() != null) {
            return user.getName();
        }
    }
    return "unknown";
}

У вищеописаному способі є 3 можливих шляхи виконання. Для отримання 100% умовного покриття нам потрібно створити 3 одиничні тести.

Java 8:

public String getName(User user) {
    return Optional.ofNullable(user)
                   .map(User::getName)
                   .orElse("unknown");
}

У цьому випадку гілки приховані, і нам потрібен лише 1 тест, щоб отримати 100% охоплення, і не має значення, у якому випадку ми будемо перевіряти. Хоча я вважаю, що все ще є ті ж 3 логічні гілки, які слід висвітлити. Я думаю, що це робить статистику умовного покриття цілком недовіреною в наші дні.

Чи є сенс вимірювати умовне покриття коду Java 8? Чи є якісь інші інструменти, які визначають недооцінений код?


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

3
Звичайно, високе умовне покриття не означає, що у нас є хороші тести, але я думаю, що ВЕЛИЧЕЗНА перевага знати, які шляхи виконання не розкриті, і саме це питання, в основному. Без умовного покриття набагато складніше помітити неперевірені сценарії. Щодо шляхів: [користувач: null], [user: notnull, user.name:null], [user: notnull, user.name:notnull]. Що мені не вистачає?
Кароль Левандовський

6
Який договір getName? Здається, що якщо userнуль, він повинен повернути "невідомо". Якщо userне є null і user.getName()є null, він повинен повернути "unknown". Якщо userце не null і user.getName()не null, він повинен повернути це. Таким чином, ви б провели тестування цих трьох випадків, оскільки саме про це укладається контракт getName. Ви, здається, робите це назад. Ви не хочете бачити філії та писати тести відповідно до цих, ви хочете писати свої тести відповідно до свого контракту та стежити за тим, щоб контракт був заповнений. Ось тоді ви маєте гарне покриття.
Вінсент Савард

1
Знову ж таки, я не кажу, що покриття доводить, що мій код є ідеально перевіреним, але це було НАДАЧНО цінним інструментом, який показує мені те, що я не перевіряв напевно. Я думаю, що контракти на тестування невіддільні від тестування шляхів виконання (ваш приклад є винятковим, оскільки він передбачає неявний мовний механізм). Якщо ви ще не перевірили шлях, то ви не повністю випробували контракт або контракт не визначений повністю.
Кароль Левандовський

2
Я повторю свій попередній пункт: це завжди так, якщо ви не обмежуєтесь лише основними мовними функціями та ніколи не викликаєте будь-яку функцію, яка не була приладнана. Що означає відсутність сторонніх бібліотек і використання SDK.
kdgregory

Відповіді:


4

Чи є інструменти, які вимірюють логічні гілки, які можна створити в Java 8?

Я не знаю жодного. Я спробував запустити код, який ви маєте через JaCoCo (він же EclEmma), щоб бути впевненим, але він показує 0 гілок у Optionalверсії. Я не знаю жодного способу його налаштування, щоб сказати інше. Якщо ви налаштували його, щоб він також включав файли JDK, він би теоретично відображав гілки Optional, але я думаю, було б нерозумно почати перевірку коду JDK. Ви просто повинні припустити, що це правильно.

Я думаю, що основна проблема полягає в тому, що я розумію, що додаткові гілки, які ви мали до Java 8, були, в певному сенсі, штучно створеними гілками. Те, що вони більше не існують у Java 8, означає, що тепер у вас є правильний інструмент для роботи (у цьому випадку Optional). У попередньому коді Java 8 вам слід було написати додаткові тести на одиницю, щоб ви могли бути впевнені, що кожна гілка коду поводиться прийнятним чином - і це стає дещо важливішим у розділах коду, які не тривіальні, як User/ getNameприклад.

У коді Java 8 ви замість цього довіряєте JDK, що код працює належним чином. Таким чином, ви повинні ставитися до цього Optionalрядка так само, як до нього відносяться інструменти покриття коду: 3 рядки з 0 гілками. У наведеному нижче коді є інші рядки та гілки - це те, на що ви просто раніше не звертали уваги, але існували кожен раз, коли ви використовували щось на зразок ArrayListабо HashMap.


2
"Щоб вони більше не існували в Java 8 ..." - Я не можу погодитися з цим, Java 8 сумісна назад ifі nullє частинами мови ;-) Ще можна писати код по-старому і передавати nullкористувач або користувач з nullім'ям. Ваші тести повинні просто довести, що контракт виконується незалежно від способу реалізації. Справа в тому, що не існує інструменту, який би сказав вам, чи ви повністю перевірили контракт.
Кароль Левандовський

1
@KarolLewandowski Я думаю, що Шаз говорить, що якщо ви довіряєте, як Optional(і пов'язані з ними методи) працюють, вам більше не доведеться їх перевіряти. Не тим самим, як ви тестували if-else: кожне ifбуло потенційним мінним полем. Optionalі подібні функціональні ідіоми вже зашифровані і гарантовано не перейдуть на вас, тому по суті є "гілка", яка зникла.
Андрес Ф.

1
@AndresF. Я не думаю, що Кароль пропонує нам тестувати Optional. Як він сказав, логічно, ми все ще повинні перевірити, чи getName()обробляє різні можливі входи таким чином, як ми маємо намір, незалежно від його реалізації. Це важче визначити, якщо інструмент покриття коду не допомагає таким чином, як це було би попередньо JDK8.
Майк Партрідж

1
@MikePartridge Так, але справа в тому, що це не робиться через покриття відділення. Покриття гілки потрібно при написанні, if-elseоскільки кожна з цих конструкцій повністю спеціальна. На відміну від цього , Optional, orElse, mapі т.д., все вже протестували. Насправді гілки «зникають», коли використовуєш більш потужні ідіоми.
Андрес Ф.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.