SonarQube, JaCoCo: (11 из 22 условий), когда их должно быть 3 (или 4) - PullRequest
1 голос
/ 18 октября 2019

Я заблудился от того, как SonarQube вычисляет условия, охватываемые тестами.

Варианты используемых инструментов: * JaCoCo 0.8.1 * SonarQube 7.4

Это мой отличный код

    boolean condition1(boolean b1, boolean b2) {
        !b1 || !b2
    }

    boolean condition2(boolean b1, boolean b2) {
        b1 || b2
    }

    boolean condition3(boolean b1, boolean b2) {
        !b1 && !b2
    }

    boolean condition4(boolean b1, boolean b2) {
        b1 && b2
    }

    boolean condition5(boolean b1, boolean b2) {
        b1 && !b2
    }

    boolean condition6(boolean b1, boolean b2, boolean b3) {
        b1 && b2 && b3
    }

Вот тесты

    void "test condition 1"() {
        expect:
        service.condition1(c1,c2)

        where:
        c1    | c2
        true  | true
        true  | false
        false | true
        false | false
    }

    void "test condition 2"() {
        expect:
        service.condition2(c1,c2)

        where:
        c1    | c2
        true  | true
        true  | false
        false | true
        false | false
    }

    void "test condition 3"() {
        expect:
        service.condition3(c1,c2)

        where:
        c1    | c2
        true  | true
        true  | false
        false | true
        false | false
    }

    void "test condition 4"() {
        expect:
        service.condition4(c1,c2)

        where:
        c1    | c2
        true  | true
        true  | false
        false | true
        false | false
    }

    void "test condition 5"() {
        expect:
        service.condition5(c1,c2)

        where:
        c1    | c2
        true  | true
        true  | false
        false | true
        false | false
    }

    void "test condition 6"() {
        expect:
        service.condition6(c1, c2, c3)

        where:
        c1    | c2    | c3
        true  | true  | true
        true  | true  | false
        true  | false | true
        true  | false | false
        false | true  | true
        false | true  | false
        false | true  | true
        false | true  | false
        false | false | false
    }

В отчете о покрытии кода говорится, что эти условия не выполнены, и единственная информация, которую я получаю, - это следующее

condition1. (11 of 22 conditions)
condition2. (7 of 14 conditions)
condition3. (11 of 22 conditions)
condition4. (7 of 14 conditions)
condition5. (9 of 18 conditions)
condition6. (11 of 22 conditions)

Это означает, что я не являюсьсмог достичь 100% покрытых тестов, хотя я считаю, логично, что.

Мне известна документация SonarQube https://docs.sonarqube.org/latest/user-guide/metric-definitions/, где написано

В каждой строке кода, содержащейВ некоторых булевых выражениях покрытие условий просто отвечает на следующий вопрос: «Было ли каждое булево выражение оценено как истинное и ложное?». Это плотность возможных условий в структурах управления потоком, которые выполнялись во время выполнения модульных тестов

Кто-нибудь имеет представление о том, как это на самом деле работает и что я здесь не так делаю?

1 Ответ

2 голосов
/ 26 октября 2019

Из похожих вопросов (например, " Почему JaCoCo не покрывает мои операторы переключателя строки? " и " Как assert groupType! = Null содержит 4 ветви ")

JaCoCo выполняет анализ байт-кода

, аналогично - посмотрите на байт-код.

Для Example.groovy

class Example {
    boolean condition2(boolean b1, boolean b2) {
        b1 || b2
    }
}

Groovy-компилятор(groovyc --version)

Groovy compiler version 3.0.0-rc-1
Copyright 2003-2019 The Apache Software Foundation. http://groovy-lang.org/

генерирует (groovyc Example.groovy) следующий байт-код (javap -v -p Example.class)

  public boolean condition2(boolean, boolean);
    descriptor: (ZZ)Z
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=4, args_size=3
         0: invokestatic  #20                 // Method $getCallSiteArray:()[Lorg/codehaus/groovy/runtime/callsite/CallSite;
         3: astore_3
         4: invokestatic  #38                 // Method org/codehaus/groovy/runtime/BytecodeInterface8.isOrigZ:()Z
         7: ifeq          25
        10: getstatic     #40                 // Field __$stMC:Z
        13: ifne          25
        16: invokestatic  #43                 // Method org/codehaus/groovy/runtime/BytecodeInterface8.disabledStandardMetaClass:()Z
        19: ifne          25
        22: goto          42
        25: iload_1
        26: ifne          33
        29: iload_2
        30: ifeq          37
        33: iconst_1
        34: goto          38
        37: iconst_0
        38: ireturn
        39: nop
        40: nop
        41: athrow
        42: iload_1
        43: ifne          50
        46: iload_2
        47: ifeq          54
        50: iconst_1
        51: goto          55
        54: iconst_0
        55: ireturn
        56: nop
        57: nop
        58: nop
        59: nop
        60: nop
        61: nop
        62: nop
        63: nop
        64: athrow
      LineNumberTable:
        line 2: 4
        line 3: 25
        line 4: 39
        line 3: 42
        line 4: 56
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      56     0  this   LExample;
            0      56     1    b1   Z
            0      56     2    b2   Z

, который содержит 14 ветвей (2 ветви на каждую команду условного перехода * 1026)* и ifne), и ваши тесты охватывают только половину из них (путь выполнения, где первый ifeq со смещением 7 переходит к смещению 25), что абсолютно соответствует тому, что сообщается JaCoCo и, следовательно, показано вSonarQube.

И здесь, по-видимому, уместно следующее обсуждение - http://groovy.329449.n5.nabble.com/Branch-coverage-issues-td5686725.html, поскольку при его компиляции с использованием опции --indy (groovyc --indy Example.groovy) получается следующий байт-код

  public boolean condition2(boolean, boolean);
    descriptor: (ZZ)Z
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=3, args_size=3
         0: iload_1
         1: ifne          8
         4: iload_2
         5: ifeq          12
         8: iconst_1
         9: goto          13
        12: iconst_0
        13: ireturn
        14: nop
        15: nop
        16: nop
        17: nop
        18: nop
        19: nop
        20: nop
        21: nop
        22: athrow
      LineNumberTable:
        line 3: 0
        line 4: 14
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      14     0  this   LExample;
            0      14     1    b1   Z
            0      14     2    b2   Z

который содержит только 4 ветви.

...