it-roy-ru.com

покрытие ветви коммутатора для коммутатора: 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% покрытие ветвей в этом случае коммутатора?

25
Gaargod

Компилятор 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 будет скорректирован в будущем.

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

31
nrainer

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

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

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

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

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

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

0
owaism