Покрытие ветви коммутатора для коммутатора: 7 из 19 пропущено
У меня есть эта система коммутации, и я использую eclemma для проверки покрытия филиала. Мы должны иметь как минимум 80% покрытия филиалов для всего, поэтому я стараюсь тестировать как можно больше. Однако, eclemma говорит мне, что эта система коммутации не полностью протестирована с точки зрения покрытия филиала.
pos = p.getCurrentPosition().substring(0, 1);
switch (pos) {
case "G":
goalkeepers++;
break;
case "D":
defense++;
break;
case "M":
midfield++;
break;
case "F":
offense++;
break;
case "S":
substitutes++;
break;
case "R":
reserves++;
break;
}
Я использовал простые тесты JUnit для прохождения каждого из этих случаев. Тем не менее, эклемма помечает это как желтый и говорит, что "7 из 19 ветвей пропущены". Я бы сказал, что есть только 7 способов пройти через эту систему переключения (6 отдельных случаев + все неопределенные).
Я попытался найти похожие вопросы по переполнению стека. Некоторые из них имели в качестве решения использовать if/else для полного охвата. Я не уверен, что это единственный способ получить это покрытие.
Кто-нибудь может объяснить, откуда берутся все эти 19 веток и как я могу протестировать эти оставшиеся 7, чтобы получить 100% покрытие ветвей в этом случае коммутатора?
2 ответа
Компилятор Java переводит код регистра переключателя в tableswitch
или к lookupswitch
, tableswitch
используется, когда есть только несколько пробелов между различными случаями. В противном случае lookupswitch
используется.
В вашем случае tableswitch
используется потому, что хэш-коды ваших дел расположены близко (в отличие от кода, на который ссылается owaism):
16: tableswitch { // 68 to 83
68: 111 // 'D'
69: 183
70: 141 // 'F'
71: 96 // 'G'
72: 183
73: 183
74: 183
75: 183
76: 183
77: 126 // 'M'
78: 183
79: 183
80: 183
81: 183
82: 171 // 'R'
83: 156 // 'S'
default: 183
}
Цифры слева от двоеточия - это упорядоченные хэш-коды и заполненные пробелы между ними, а цифры справа - места назначения прыжка. (В Java хеш-код символа является его значением ASCII.)
68
это хэш-код "D" (самый низкий), и 83
это хэш-код "S" (самый высокий). 69
является значением одного из промежутков между реальными случаями и будет переходить к случаю по умолчанию.
Однако я предполагаю, что EclEmma исключает эти ветви из вычисления покрытия tableswitch
(это могло бы снизить охват еще больше из-за пробелов). Итак, у нас еще 0 (подсчитанных) веток.
Затем выполняется сравнение с равным значением строки в каждом месте назначения перехода (кроме одного случая по умолчанию). Поскольку ваш коммутатор состоит из 6 случаев, у нас есть 6 пунктов назначения для шести прыжков со сравнением равных.
Байт-код сравнения для случая "G" ниже:
96: aload_3
97: ldc #10
99: invokevirtual #11 java/lang/Object;)Z
102: ifeq 183
105: iconst_0
106: istore 4
108: goto 183
111: aload_3
EclEmma считает две ветви: либо входная строка и строка регистра равны, либо нет. Таким образом, у нас есть 6 * 2 веток для сравнения. (Случай по умолчанию не разветвляется.)
Далее, если две строки равны, индекс регистра будет сохранен (строки байтового кода 105-106
для случая "G"). Потом прыжок ко второму tableswitch
будет выполнен. В противном случае прыжок будет выполнен напрямую.
185: tableswitch { // 0 to 5
0: 224
1: 237
2: 250
3: 263
4: 276
5: 289
default: 299
}
Этот переключатель работает с ранее сохраненным регистром регистра и переходит к коду в регистре (регистр "G" имеет индекс 0
случай по умолчанию имеет -1
). EclEmma насчитывает 7 ветвей (6 случаев плюс случай по умолчанию).
Следовательно, у нас 0 подсчитанных ветвей в первом tableswitch
12 филиалов в equals
сравнения и еще 7 веток во втором tableswitch
, В целом, это приводит к 19 филиалам.
Ваши тесты не охватывают ни одну из 6 не равных ветвей. Чтобы покрыть их, вам нужно будет найти строку для каждого случая, которая не равна условию случая, но имеет тот же хэш-код. Это возможно, но определенно не разумно...
Возможно, подсчет веток EclEmma будет скорректирован в будущем.
Более того, я полагаю, что у вас нет тестового примера, который не соответствует ни одному из случаев (таким образом, (неявный) случай по умолчанию не рассматривается.)
Проверьте следующую ссылку: http://sourceforge.net/p/eclemma/discussion/614869/thread/80e770df/
Ниже приведен фрагмент вышеуказанной ссылки:
Это для примера, имеющего переключатель с 3 случаями:
Это довольно интересное наблюдение. Из байт-кода видно, как компилятор Java обрабатывает переключение в строках. На самом деле это трехэтапный процесс:
- Включите хэш-код (3 ветви, 1 по умолчанию)
- Для каждого хеш-кода делайте равные (3 * 2 ветви)
- Выполните окончательное переключение для фактического выполнения дел (3 ветви, 1 по умолчанию)
Таким образом, у нас есть всего 14 ветвей, что выглядит странно с точки зрения исходного кода. Что выглядит еще более странным, так это то, что вам не хватает трех из них. Объяснение - это шаг 2, где метод equals применяется дополнительно после хеш-кода. Чтобы покрыть эти ветви, вам также нужно найти другие строки с таким же хеш-кодом. Это определенно то, что может быть отфильтровано из отчетов о покрытиях в будущих версиях JaCoCo:
https://sourceforge.net/apps/trac/eclemma/wiki/FilteringOptions