PowerMockito 模拟间接静态方法
PowerMockito mock indirect static method
Class 测试
public class Randomer {
public int get() {
return (int) Math.random() + 1;
}
}
测试class
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>
这里出了什么问题?老实说,每当我遇到模拟静态函数的情况时,我都会尝试找到解决方法而不是浪费时间。所以需要你的帮助来找出确切的解决方案。
示例 classes 的唯一目的是演示 Math.random() 函数未被模拟,因此不会返回所需的值。
一般实现
模拟是编写测试时必不可少的工具。尽管对实例的模拟工作完全符合预期,但模拟静态方法似乎真的很复杂,因为模拟库的组合如此之多,而且选项如此之多,只能支持几个简单的场景。这应该是精简的。
使用的库:
- mockito-all-1.9.5.jar
- powermock-mockito-release-full-1.5.1-full.jar
此测试通过,从而证明静态调用 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
这里似乎有一个库不匹配。
在您声明使用以下依赖项的评论中(不方便使用 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>
Class 测试
public class Randomer {
public int get() {
return (int) Math.random() + 1;
}
}
测试class
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>
这里出了什么问题?老实说,每当我遇到模拟静态函数的情况时,我都会尝试找到解决方法而不是浪费时间。所以需要你的帮助来找出确切的解决方案。
示例 classes 的唯一目的是演示 Math.random() 函数未被模拟,因此不会返回所需的值。
一般实现
模拟是编写测试时必不可少的工具。尽管对实例的模拟工作完全符合预期,但模拟静态方法似乎真的很复杂,因为模拟库的组合如此之多,而且选项如此之多,只能支持几个简单的场景。这应该是精简的。
使用的库:
- mockito-all-1.9.5.jar
- powermock-mockito-release-full-1.5.1-full.jar
此测试通过,从而证明静态调用 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
这里似乎有一个库不匹配。
在您声明使用以下依赖项的评论中(不方便使用 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>