PowerMock ECLemma 覆盖问题

Posted

技术标签:

【中文标题】PowerMock ECLemma 覆盖问题【英文标题】:PowerMock ECLEmma coverage issue 【发布时间】:2014-06-15 07:19:49 【问题描述】:

我们在 JUnit 中使用 EasyMock 和 PowerMock。使用的覆盖工具是 ECLEmma。使用 EasyMock,它以绿色正确显示覆盖范围(如已覆盖)。但是,对于使用 PowerMock 进行单元测试的代码,覆盖率显示为红色(未覆盖)。在网上阅读过类似的问题。但是,只是想检查是否有解决方案。

谢谢 文卡特斯

【问题讨论】:

把你的powermock测试逻辑放在测试包内的其他简单java类中,并从测试类中调用merhod,增加应用程序的代码覆盖率。 【参考方案1】:

是的,有一个解决方案:

首先你必须添加这个maven依赖:

<dependency>
  <groupId>org.powermock</groupId>
  <artifactId>powermock-module-junit4-rule-agent</artifactId>
  <version>1.6.4</version>
  <scope>test</scope>
</dependency>

然后,不要使用这个注解@RunWith(PowerMockRunner.class),只需像这样在Test类中添加一个@Rule:

public class Test 

   @Rule
   public PowerMockRule rule = new PowerMockRule();

您可以在此博客中找到更多信息Make EclEmma test coverage work with PowerMock

【讨论】:

你能指导一下吗?***.com/questions/52064126/…【参考方案2】:

这是一个已知问题:https://github.com/jayway/powermock/issues/422

而且已经很久了,不会很快修复的。

我建议你改用eCobertura。

【讨论】:

在切换之前请注意 eCobertura 的限制:bitbucket.org/jmhofer/ecobertura/… eCobertura 插件似乎不再维护 为了解决这个问题,我最终将所有使用 PowerMocikito.staticMock 的测试拆分到单独的类文件中,这样覆盖问题就不会扩散到我的所有测试中。【参考方案3】:

这在我的项目中的大多数情况下都有效:

@Rule
public PowerMockRule rule = new PowerMockRule();
static 
    PowerMockAgent.initializeIfNeeded();

删除/评论 @RunWith(PowerMockRunner.class) 并在您的类路径中添加 powermock-module-javaagent-1.6.5.jar 后包括以下导入:

import org.junit.Rule;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.powermock.modules.agent.PowerMockAgent;

现在右键单击->Coverage As->Coverage Configurations 并在 Arguments 中添加以下行:

-ea -noverify -javaagent:path/to/powermock-module-javaagent-1.6.5.jar

点击应用->覆盖范围。

还要注意@Before 在这种情况下不起作用,因此您必须从标有@Before 的方法中添加标有@Test 的方法中的所有内容。

【讨论】:

【参考方案4】:

我们有一个要模拟的静态类。使用模拟静态类,eclEmma 代码覆盖率插件在 Eclipse 中不起作用。所以我们所做的是,所以将 @RunWith(JUnit4.class) (而不是 @RunWith(PowerMockRunner.class) )放在类之前,并将以下几行放在类中

static 
PowerMockAgent.initializeIfNeeded();


@Rule
public PowerMockRule rule = new PowerMockRule();

编译类并运行测试类。代码覆盖率适用于课堂。此更改仅在 Eclipse IDE 中。

编写测试用例后,我们将代码恢复正常。放置 @RunWith(PowerMockRunner.class) 而不是 @RunWith(JUnit4.class) 并在静态代码和 powermockrule 行上方注释。

【讨论】:

【参考方案5】:

我已经设法使用 powermock-module-javaagent 使用 Jacoco 生成 PowerMock 覆盖范围。

只需确保将 powermock 代理放在 jacoco 代理之后:

<artifactId>maven-surefire-plugin</artifactId>
            <configuration>
                <useSystemClassLoader>true</useSystemClassLoader>
                <argLine>$jacocoArgLine -javaagent:$settings.localRepository/org/powermock/powermock-module-javaagent/$powermock.version/powermock-module-javaagent-$powermock.version.jar -noverify</argLine>
...

如果你想看一个例子,看看这个项目:https://github.com/jfcorugedo/sonar-scanner

在这里您可以看到声纳考虑了静态方法和被 PowerMock 模拟的 new 语句:

如果您想模拟 newstatements,请确保使用 PowerMockRule 而不是 PowerMockRunner

看看this test

【讨论】:

【参考方案6】:

更新 powermock 版本修复我的问题是支持版本的 maven 依赖

<dependency>
   <groupId>org.powermock</groupId>
   <artifactId>powermock-module-junit4-rule-agent</artifactId>
   <version>1.7.3</version>
   <scope>test</scope>
</dependency>

希望对你有帮助!!!

【讨论】:

【参考方案7】:

我遇到了同样的问题。所以,我更新了 powerMockito 版本。现在我使用的是 Power mock 1.7.4 版和 Jacoco 0.8.5 版。它甚至也在 eclipse 上工作。

【讨论】:

【参考方案8】:

这里有一些更详细的全班答案。

需要注意的几点:

    我必须使用spy 而不是mockStatic

    我不得不将@PrepareForTest 移到方法级别。

    正如其他答案中提到的那样,我还必须添加以下依赖项

    org.powermock:powermock-module-junit4-rule-agent:2.0.9

以下是我的完整课程代码供参考:

import java.util.ArrayList;
import java.util.Arrays;

import org.elasticsearch.action.ActionFuture;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.Client;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.agent.PowerMockAgent;
import org.powermock.modules.junit4.rule.PowerMockRule;

import org.opensource.dummy.config.DummyConfig;
import org.opensource.dummy.data.builder.DataBuilder;
import org.opensource.dummy.model.SampleRequest;
import org.opensource.dummy.model.SampleType;
import org.opensource.dummy.model.Item;
import org.opensource.dummy.model.RequestType;

@RunWith(JUnit4.class)
public class MockedDataSearchServiceHelperTest 

    static 
        PowerMockAgent.initializeIfNeeded();
    

    @Rule
    public PowerMockRule rule = new PowerMockRule();

    @PrepareForTest( DummyConfig.class )
    @SuppressWarnings("unchecked")
    @Test
    public void testSearchResponseValid() throws Exception 
        Item Item = DataBuilder.createItem("2024-01-24", "2024-12-25", "61ef8faebec3bb72fbcf336d", null);
        SampleRequest sampleRequest = DataBuilder.createSampleRequest(Arrays.asList(Item),
                DataBuilder.createDeliveryMetrics(1), null, RequestType.ITEM);

        BoolQueryBuilder boolQueryBuilder = DataSearchServiceHelper.createCustomQuery(sampleRequest, Item);

        SearchRequestBuilder searchRequestBuilder = PowerMockito.mock(SearchRequestBuilder.class);
        ActionFuture<SearchResponse> actionFuture = PowerMockito.mock(ActionFuture.class);

        Client client = PowerMockito.mock(Client.class);

        PowerMockito.spy(DummyConfig.class);
        PowerMockito.doReturn(client).when(DummyConfig.class, "getClient");

        Mockito.when(client
                .prepareSearch(new String[]  "dummy" ))
                .thenReturn(searchRequestBuilder);
        Mockito.when(searchRequestBuilder.setIndicesOptions(IndicesOptions.LENIENT_EXPAND_OPEN))
                .thenReturn(searchRequestBuilder);
        Mockito.when(searchRequestBuilder.setQuery(Mockito.any(QueryBuilder.class))).thenReturn(searchRequestBuilder);

        Mockito.when(searchRequestBuilder.execute()).thenReturn(actionFuture);

        Mockito.when(actionFuture.actionGet()).thenReturn(new SearchResponse(null, null, 0, 0, 0, 0, null, null));

        SearchResponse searchResponse = DataSearchServiceHelper.getSearchResponse(
                new String[]  "dummy" ,
                boolQueryBuilder, DataBuilder.createDeliveryMetrics(1), RequestType.ITEM);

        Assert.assertNotNull(searchResponse);
    

我希望这对某人有所帮助。

【讨论】:

【参考方案9】:

对于模拟静态类,使用 @RunWith(PowerMockRunner.class) 并在 Eclipse 上运行“Coverage As JUnit 测试”确实会显示已覆盖的代码未覆盖,这显然是个问题。

要添加到上面的解决方案,在一个maven项目中,你可以试试这个..

在根pom.xml 中,为生成报告,添加html 作为cobertura-maven-plugin 中的格式。下面是它的外观。

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>cobertura-maven-plugin</artifactId>
    <configuration>
       <formats>
          <format>html</format>
          <format>xml</format>
       </formats>
    </configuration>
</plugin>

然后,转到您的类所在的模块并在 Eclipse Web 浏览器或您选择的一个中打开 target/site/cobertura/index.html 文件。您可以在那里找到覆盖范围信息。

【讨论】:

能否指导一下“Emma”代码覆盖率工具?

以上是关于PowerMock ECLemma 覆盖问题的主要内容,如果未能解决你的问题,请参考以下文章

在Java中使用EclEmma插件进行代码覆盖率检测

如何用powermockrunner覆盖循环

在Eclipse/STS中使用EclEmma进行覆盖率检查

EclEmma测试代码覆盖率使用案例

Android单元测试系列-Mock之PowerMock

Software Testing使用JUnit以及Eclemma进行单元测试和覆盖测试