【问题标题】:PowerMockito mock indirect static methodPowerMockito 模拟间接静态方法
【发布时间】:2017-09-15 08:29:23
【问题描述】:

要测试的类

public class Randomer {
    public int get() {
        return (int) Math.random() + 1;
    }
}

测试类

package org.samiron;

import static org.junit.Assert.assertEquals;

import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.api.support.membermodification.MemberMatcher;
import org.powermock.api.support.membermodification.MemberModifier;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.testng.annotations.Test;

/**
 * @author samiron
 *
 */
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Randomer.class, Math.class })
public class RandomerTest {

    @Test
    public void shouldAddUpDieRollsCorrectly() throws Exception {
        PowerMockito.spy(Math.class);
        MemberModifier.stub(MemberMatcher.method(Math.class, "random")).toReturn(2.0);
        Randomer d = new Randomer();
        assertEquals(3, d.get());
    }
}

总是收到java.lang.AssertionError: expected:<3> but was:<1>

这里出了什么问题?老实说,每次我遇到模拟静态函数的情况时,我都会尝试找到解决方法而不是浪费时间。所以需要你的帮助来找出确切的解决方案。

示例类的唯一目的是证明 Math.random() 函数没有被模拟,因此没有返回所需的值。

一般实现

模拟是编写测试时必不可少的工具。尽管模拟实例的工作方式与预期的一样,但是模拟静态方法似乎真的很复杂,因为模拟库的组合如此之多,而且支持几个简单场景的选项如此之多。这应该被简化。

使用的库:

  • mockito-all-1.9.5.jar
  • powermock-mockito-release-full-1.5.1-full.jar

【问题讨论】:

  • 那么,您是否可以选择重构,以便将Math.random() 调用封装在可以正确模拟的类/方法中?
  • 另外,Math.random() 应该返回一个介于[0.0...1.0) 之间的值。那你为什么要嘲笑返回2.0的方法呢?
  • 您的代码对我有用。你的依赖是什么?
  • @LucianovanderVeekens 我用我正在使用的罐子更新了 OP,可能是我使用的组合有问题。不幸的是,这里没有专家(请不要感到震惊!)。

标签: java unit-testing junit mockito powermock


【解决方案1】:

此测试通过,从而证明静态调用 Math.random() 成功模拟:

@RunWith(PowerMockRunner.class)
// tell PowerMock about (a) the class you are going to test and (b) the class you are going to 'mock static'
@PrepareForTest({Randomer.class, Math.class })
public class RandomerTest {

    @Test
    public void shouldAddUpDieRollsCorrectly() throws Exception {
        // prepare PowerMock for mocking statics on Math
        PowerMockito.mockStatic(Math.class);
        // establish an expectation for what Match.random() should return
        PowerMockito.when(Math.random()).thenReturn(2.0);

        Randomer d = new Randomer();

        assertEquals(3, d.get());
    }
}

这与您在问题中发布的主要区别在于我使用的是...

  • PowerMockito.mockStatic(Math.class)PowerMockito.when(Math.random()).thenReturn(2.0)

...而不是:

  • PowerMockito.spy(Math.class)MemberModifier.stub(MemberMatcher.method(Math.class, "random")).toReturn(2.0)

此外,在您的 OP 中,示例代码混合使用了 JUnit (org.powermock.modules.junit4.PowerMockRunner) 和 TestNG (org.testng.annotations.Test),而在我的示例中,我只是使用 JUnit。

以上已通过验证

  • junit:4.12
  • powermock-module-junit4:1.7.0
  • powermock-api-mockito2:1.7.0

【讨论】:

  • 感谢您的回复。正如您和卢西亚诺指出的那样,我正在使用的库似乎有问题。我添加了我正在使用的罐子,如果这个组合有什么问题,你有什么提示吗?
【解决方案2】:

这里似乎有一个库不匹配。

在您声明使用以下依赖项的 cmets 中(没有 Maven 的便利):

<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-all</artifactId>
  <version>1.9.5</version>
  <scope>test</scope>
</dependency>

<dependency>
  <groupId>org.powermock</groupId>
  <artifactId>powermock-mockito-release-full</artifactId>
  <version>1.5.1</version>
  <scope>test</scope>
</dependency>

我让你的代码使用这些:

<dependency>
  <groupId>org.powermock</groupId>
  <artifactId>powermock-module-junit4</artifactId>
  <version>1.7.0</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.powermock</groupId>
  <artifactId>powermock-api-mockito</artifactId>
  <version>1.7.0</version>
  <scope>test</scope>
</dependency>

【讨论】:

  • 所以我的代码不适用于第一个依赖项吧?
  • @Samiron 我会用我建议的依赖项替换这两个依赖项。
  • 毫无疑问,我正在这样做。感谢您的答复。但我只是想确保我的组合有问题,对吗?确切地知道为什么这种组合不起作用也很好。
  • @Samiron 好吧,我想说powermock-mockito-release-full 包含一个错误,因为旧版本的 powermock 也不适合我。而且,那个依赖不再更新了,最新的版本是2015年的。可能已经重命名了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-07
  • 1970-01-01
  • 2014-06-29
相关资源
最近更新 更多