Подтвердить что ты не робот

Охват ветки eclemma для коммутатора: 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 для прохождения каждого из этих случаев. Тем не менее eclemma отмечает это как желтый и говорит "7 из 19 веток пропустили". Я бы сказал, что есть всего 7 способов пройти через эту коммутационную систему (6 отдельных случаев + все undefined).

Я попытался найти похожие вопросы о переполнении стека. Некоторые из них были в качестве решений для использования, если/для полного охвата. Я не уверен, что это единственный способ получить этот охват.

Может кто-нибудь объяснить, откуда берутся все эти 19 ветвей и как я могу проверить оставшиеся 7, чтобы получить 100% -ный охват ветки в этом случае коммутатора?

4b9b3361

Ответ 1

Компилятор 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 рассчитывает две ветки: либо входная строка, и строка case равны, либо они не являются. Таким образом, для сравнений мы имеем 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 ветвей без равенства. Чтобы их охватить, вам нужно найти строку для каждого случая, которая не равна условию case, но имеет тот же хэш-код. Возможно, но окончательно неразумно...

Вероятно, подсчет ветвей EclEmma будет скорректирован в будущем.

Кроме того, я полагаю, у вас нет тестового примера, который не соответствует ни одному из случаев (таким образом, (неявный) случай по умолчанию не распространяется.)

Ответ 2

Проверьте следующую ссылку: http://sourceforge.net/p/eclemma/discussion/614869/thread/80e770df/

Ниже приведен фрагмент из приведенной выше ссылки:

Это пример, имеющий переключатель с тремя случаями:

Это довольно интересное замечание. От взгляда на байт кода можно увидеть, как компилятор Java обрабатывает переключатель на строках. На самом деле это трехэтапный процесс:

  • Включить хэш-код (3 ветки, 1 по умолчанию)
  • Для каждого хэш-кода выполните равенства (3 * 2 ветки)
  • Сделайте окончательный переключатель для фактического выполнения дел (3 ветки, 1 по умолчанию)

Итак, у нас есть в общей сложности 14 ветвей, которые выглядят странный с точки зрения исходного кода. Что еще выглядит Странно, что вам не хватает трех из них. Объяснение - шаг 2, где метод equals применяется дополнительно после хэш-кода. Чтобы охватить эти ветки, вам также нужно найти другие строки с тот же хеш-код. Это определенно то, что может быть отфильтрован из отчетов о покрытиях в будущих версиях JaCoCo:
https://sourceforge.net/apps/trac/eclemma/wiki/FilteringOptions