Почему JaCoCo не закрывает мои инструкции для операторов String?

У меня есть оператор switch, который извлекает режим адресации из String, и я написал модульные тесты для покрытия, что я думал о каждом событии, но JaCoCo, похоже, пропускает мои инструкции switch, что приводит к снижению охват.

Почему, если все мои операторы case, в том числе по умолчанию, выполняются в тестах, будет ли оператор switch не считаться ударом?

(см. результаты тестов, отображаемые в CodeCov)

enter image description here

Ответ 1

Для переключателя по строке

class Fun  {
  static int fun(String s) {
    switch (s) {
      case "I":
        return 1;
      case "A":
        return 2;
      case "Z":
        return 3;
      case "ABS":
        return 4;
      case "IND":
        return 5;
      default:
        return 6;
    }
  }
}

Компилятор Oracle Java генерирует байт-код, похожий на следующий код (Eclipse Compiler for Java генерирует несколько другой байт-код)

    int c = -1;
    switch (s.hashCode()) {
      case 65: // +1 branch
        if (s.equals("I")) // +2 branches
          c = 0;
        break;
      case 73: // +1 branch
        if (s.equals("A")) // +2 branches
          c = 1;
        break;
      case 90: // +1 branch
        if (s.equals("Z")) // +2 branches
          c = 2;
        break;
      case 64594: // +1 branch
        if (s.equals("ABS")) // +2 branches
          c = 3;
        break;
      case 72639: // +1 branch
        if (s.equals("IND")) // +2 branches
          c = 4;
        break;
      default: // +1 branch
    }
    switch (c) {
      case 0: // +1 branch
        return 1;
      case 1: // +1 branch
        return 2;
      case 2: // +1 branch
        return 3;
      case 3: // +1 branch
        return 4;
      case 4: // +1 branch
        return 5;
      default: // +1 branch
        return 6;
    }

Итак, исходный оператор switch с 6 случаями представлен в байт-кодере с помощью переключателя с 6 случаями для hashCode of String плюс 5 if-statements плюс еще один переключатель с 6 случаями. Чтобы увидеть этот байт-код, вы можете использовать javap -c.

JaCoCo выполняет анализ байт-кода и в версиях ниже 0.8.0 не имеет фильтра для переключения по строкам. Ваши тесты охватывают случаи, когда условия в if-statements оцениваются до true, но не в тех случаях, когда они оцениваются до false. Лично я бы посоветовал просто игнорировать недостающие случаи, потому что цель состоит не в том, чтобы проверить, что компилятор генерирует правильный код, а для проверки правильности поведения вашего приложения. Но ради полноты этого ответа - вот тесты, которые охватывают все ветки байткода:

import org.junit.Test;
import static org.junit.Assert.*;

public class FunTest {
  @Test
  public void test() {
    // original strings:
    assertEquals(1, Fun.fun("I"));
    assertEquals(2, Fun.fun("A"));
    assertEquals(3, Fun.fun("Z"));
    assertEquals(4, Fun.fun("ABS"));
    assertEquals(5, Fun.fun("IND"));

    // same hash codes, but different strings:
    assertEquals(6, Fun.fun("\0I"));
    assertEquals(6, Fun.fun("\0A"));
    assertEquals(6, Fun.fun("\0Z"));
    assertEquals(6, Fun.fun("\0ABS"));
    assertEquals(6, Fun.fun("\0IND"));

    // distinct hash code to cover default cases of switches
    assertEquals(6, Fun.fun(""));
  }
}

И отчет, созданный JaCoCo 0.7.9 в качестве доказательства:

отчет о покрытии

JaCoCo версии 0.8.0 предоставляет фильтры, включая фильтр для байт-кода, который javac производит для переключения по строка. И поэтому генерирует следующий отчет даже без дополнительных тестов:

отчет о покрытии