为什么 Spring @Service 方法在 JaCoCo 中以 0% 的代码覆盖率出现?

Why Spring @Service methods appear with 0% code coverage in JaCoCo?

已加载这些库:

只有元素 "static {...}" 以 100% 的覆盖率出现。其余所有为 0%:

单元测试 class 有注释 @ExtendWith(SpringExtension.class)@AutoConfigureMockMvc。该服务注入 @Mock.

doReturn(actual).when(service).get(param);
when(service.get(param)).thenReturn(actual);

expected = service.get(param);
verify(service, times(1)).get(param);

assertEquals(expected, actual);
assertEquals(actual, expected);

我的ServiceImplclass点击任何方法都是红色的。它扩展了一个抽象class。 Jackson 的 ObjectMapper 是红色的,也是方法中的整行。例如:

public CustomReturnObject get(final CustomParamObject paramObject) {
    try {
        return retryTemplate.execute(status -> {
            String json = repository.get(paramObject);
            CustomReturnObject returnObject = json2CustomObject(json, paramObject);

            if (returnObject == null) {
                returnObject = new CustomReturnObject();
                returnObject.setId(paramObject.getId());
            }

            return returnObject;
        });
    } catch (Exception ex) {
        log.error(ex.getMessage(), ex);
        return null;
    }
}

类似,让我们把 Spring 搁置一旁,因为 IMO 显然有问题 expectations/understanding 关于这里的核心问题 - 嘲笑。

doReturn(actual).when(service).get(param);
expected = service.get(param);
verify(service, times(1)).get(param);
assertEquals(expected, actual);

你不是在测试 get 方法,你是在测试总是 returns actual 的东西,不管 get 中实际写的是什么,因为在这种情况下它没有被执行。

这里complete example作为证明:

src/main/java/hello/GreetingService.java:

package hello;

class GreetingService {

  Object get(Object param) {
    throw new UnsupportedOperationException();
  }

}

src/test/java/hello/GreetingServiceTest.java:

package hello;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;

@ExtendWith(MockitoExtension.class)
public class GreetingServiceTest {

  @Mock
  public GreetingService service;

  @Test
  void test() {
    Object param = new Object();
    Object actual = new Object();

    doReturn(actual).when(service).get(param);
    Object expected = service.get(param);
    verify(service, Mockito.times(1)).get(param);
    assertEquals(expected, actual);
  }

}

build.gradle :

apply plugin: 'java'

sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    testCompile 'org.mockito:mockito-junit-jupiter:2.23.4'
}

真正的方法get抛出UnsupportedOperationException,但是上面的测试成功了,所以真正的方法没有被执行。作为证明 get 未执行的另一种方法:将断点放入其中并在调试模式下从 IDE 执行测试 - 断点不会到达。

覆盖率显示了真正执行的内容,因此对于未执行的方法来说它是零是绝对正确的。