2015-01-18 5 views
24

У меня есть эта система переключения, и я использую eclemma для проверки охвата филиала. Мы обязаны иметь по крайней мере 80% в охвате филиалов для всего, поэтому я пытаюсь проверить как можно больше. Однако, eclemma говорит мне, что эта система переключения не полностью протестирована с точки зрения охвата филиалов.eclemma покрытие для коммутатора: 7 из 19 пропущенных

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 отдельных случаев + все неопределенные).

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

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

+0

Есть ли шансы 'пос '_variable_ может получить другие буквенные значения? Если да, добавьте случай по умолчанию. – Voqus

+0

Я добавил первую строку кода, в которой указано, как pos определен. Добавление пустого случая по умолчанию ничего не изменило, как я ожидал бы – Gaargod

+0

Я бы посоветовал не тестировать другие ветки. Некоторые конструкции (см. Также Java 7s try with resource) генерируют гораздо более сложный байт-код, чем исходный код. Однако вы можете быть на 100% (нормально 99,99%) уверены, что JRE не ошибается в этом. Поэтому сосредоточьте свои усилия на тестировании в другом месте. – Thirler

ответ

29

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 (count) ветвей еще.

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

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

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

+1

Спасибо за приятное объяснение. Сообщает вам, почему байт-код инструментария - плохой способ увидеть тестовое покрытие кода * source *; компилятор обязательно «добавляет детали» в уточнение от абстрактного (исходного кода) к реализации (байтовый код). Эта дополнительная деталь не является частью интенции исходного приложения. –

+1

Этот ответ является полезным фоном для разных стилей инструментов: stackoverflow.com/questions/15255798/what-are-the-differences-between-the-three-methods-of-code-coverage-analysis Существуют инструменты для тестирования, которые вычисляют с использованием только исходного кода; у них не было бы этой проблемы. Вот несколько: (наш) инструмент Java Test Coverage (semanticdesigns.com/Products/TestCoverage), клевер (https://www.atlassian.com/software/clover/overview) и glenmccl.com/instr/index.htm –

+0

Спасибо, что вы нашли время, чтобы объяснить это. Хотя это не решает мою проблему, я теперь понимаю, почему и как я могу обойти это. Я попытаюсь изменить свои методы таким образом, чтобы получить 80%. – Gaargod

0

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

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

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

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

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

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

+0

Я видел это, когда искал проблему, но мне было немного непонятно, как я могу просто покрыть эти ветви. Верно ли, что, если компилятор действительно выполняет 4 теста, и мне нужно все, что нужно, мне нужно сделать тесты, равные более чем двум случаям? Они говорят о хэш-кодах строк. Как я могу использовать их, чтобы получить эту ситуацию в случае коммутатора довольно простым способом? – Gaargod

+0

@Gaargod: вам нужно будет указывать для каждого оператора switch, какие дополнительные записи байт-кода были добавлены для компилятора. Я сомневаюсь, что вы действительно хотите это сделать, или что вы можете сделать это в любом практическом (например, скромном инвестировании времени). Вы хотите, чтобы инструмент сообщал информацию о том, что находится в вашем исходном коде. Это не так. Не счастливое состояние. –

+0

см. Https://github.com/jacoco/jacoco/pull/496. Опция фильтрации должна быть доступна в '0.7.10' – Julien

Смежные вопросы