PowerMock测试
2016-07-07 18:17
363 查看
EasyMock可以满足单元测试中的大部分需求,但是由于动态代理是使用了面向对象的继承和多态特性,JDK自身的动态代理只针对接口进行代理,其本质是为接口生成一个实现类,而CGLIB可以针对类进行代理,其本质是将类自身作为基类。
如果遇到了静态、final类型的类和方法,以及私有方法,EasyMock的动态代理局限性使得无法测试这些特性情况。
PowerMock是在EasyMock基础上进行扩展(只是补充,不是替代),使用了字节码操作技术直接对生成的字节码类文件进行修改,从而可以方便对静态,final类型的类和方法进行Mock,还可以对私有方法进行Mock,更可以对类进行部分Mock。
PowerMock的工作过程和EasyMock类似,不同之处在于需要在类层次声明@RunWith(PowerMockRunner.class)注解,以确保使用PowerMock框架引擎执行单元测试。
通过如下方式在maven添加PowerMock相关依赖:
[html] view plain copy
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-easymock</artifactId>
<version>1.5.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.5.1</version>
<scope>test</scope>
</dependency>
例子如下:
(1).Miock final类的静态方法:
如果测试代码中使用到了java.lang.System类,代码如下:
[java] view plain copy
public class SystemPropertyMockDemo {
public String getSystemProperty() throws IOException {
return System.getProperty("property");
}
}
如果对System.getProperty()方法进行Mock,代码如下:
[java] view plain copy
@RunWith(PowerMockRunner.class)
@PrepareForTest({SystemPropertyMockDemo.class})//声明要Mock的类
public class SystemPropertyMockDemoTest {
@Test
public void demoOfFinalSystemClassMocking() throws Exception {
PowerMock.mockStatic(System.class);//Mock静态方法
EasyMock.expect(System.getProperty("property")).andReturn("my property");//录制Mock对象的静态方法
PowerMock.replayAll();//重放Mock对象
Assert.assertEquals("my property",
new SystemPropertyMockDemo().getSystemProperty());
PowerMock.verifyAll();//验证Mock对象
}
}
非final类的静态方法代码相同,注意(上述代码只能在EasyMock3.0之后版本正常运行)
如果要在EasyMock3.0之前版本正常Mock final类的静态方法,需要使用PowerMockito,
通过如下方式在maven中添加PowerMockito相关依赖:
[html] view plain copy
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.5.1</version>
<scope>test</scope>
</dependency>
代码如下:
[java] view plain copy
@RunWith(PowerMockRunner.class)
@PrepareForTest({SystemPropertyMockDemo.class})
public class SystemPropertyMockDemoTest {
@Test
public void demoOfFinalSystemClassMocking() throws Exception {
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getProperty("property")).thenReturn("my property");
PowerMock.replayAll();
Assert.assertEquals("my property",
new SystemPropertyMockDemo().getSystemProperty());
PowerMock.verifyAll();
}
}
注意:
对于JDK的类如果要进行静态或final方法Mock时,@PrepareForTest()注解中只能放被测试的类,而非JDK的类,如上面例子中的SystemPropertyMockDemo.class。
对于非JDK的类如果需要进行静态活final方法Mock时, @PrepareForTest()注解中直接放方法所在的类,若上面例子中的System不是JDK的类,则可以直接放System.class。
@PrepareForTest({......}) 注解既可以加在类层次上(对整个测试文件有效),也可以加在测试方法上(只对测试方法有效)。
(2).Mock非静态的final方法:
被测试代码如下:
[java] view plain copy
public class ClassDependency {
public final boolean isAlive() {
return false;
}
}
public class ClassUnderTest{
public boolean callFinalMethod(ClassDependency refer) {
return refer.isAlive();
}
}
使用PowerMock的测试代码如下:
[java] view plain copy
@RunWith(PowerMockRunner.class)
public class FinalMethodMockDemoTest {
@Test
@PrepareForTest(ClassDependency.class)
public void testCallFinalMethod() {
ClassDependency depencency = PowerMock.createMock(ClassDependency.class); //创建Mock对象
ClassUnderTest underTest = new ClassUnderTest();
EasyMock.expect(depencency.isAlive()).andReturn(true);
PowerMock.replayAll();
Assert.assertTrue(underTest.callFinalMethod(depencency));
PowerMock.verifyAll();
}
}
(3)部分Mock和私有方法Mock:
如果被测试类某个方法不太容易调用,可以考虑只对该方法进行Mock,而其他方法全部使用被测试对象的真实方法,可以考虑使用PowerMock的部分Mock,被测试代码如下:
[java] view plain copy
public class DataService {
public boolean replaceData(final String dataId, final byte[] binaryData) {
return modifyData(dataId, binaryData);
}
public boolean deleteData(final String dataId) {
return modifyData(dataId, null);
}
private boolean modifyData(final String dataId, final byte[] binaryData) {
return true;
}
}
只对modifyData方法进行Mock,而其他方法调用真实方法,测试代码如下:
[java] view plain copy
@RunWith(PowerMockRunner.class)
@PrepareForTest(DataService.class)
public class DataServiceTest {
@Test
public void testReplaceData() throws Exception {
DataService tested = PowerMock.createPartialMock(DataService.class, “modifyData”);//创建部分mock对象,只对modifyData方法Mock
PowerMock.expectPrivate(tested, “modifyData”, “id”, null).andReturn(true);//录制私有方法
PowerMock.replay(tested);
assertTrue(tested.deleteData(“id”));
PowerMock.verify(tested);
}
}
部分Mock在被测试方法的依赖在同一个类,且不容易创建时比较有用。
个人认为私有方法的Mock意义不是很大,完全可以使用反射机制直接调用。
(4).调用对象的构造方法Mock对象:
在被测试方法内部调用构造创建了一个对象很常见,被测试代码如下:
[java] view plain copy
public class PersistenceManager {
public boolean createDirectoryStructure(String directoryPath) {
File directory = new File(directoryPath);
if (directory.exists()) {
throw new IllegalArgumentException("\"" + directoryPath + "\" already exists.");
}
return directory.mkdirs();
}
}
创建文件操作(new File(path))依赖与操作系统底层实现,如果给定的路径不合法,将会出现异常导致测试无法正常覆盖,此时需要使用PowerMock的提供的调用构造方法创建Mock对象,测试代码如下:
[java] view plain copy
@RunWith(PowerMockRunner.class)
@PrepareForTest( PersistenceManager.class )
public class PersistenceManagerTest {
@Test
public void testCreateDirectoryStructure_ok() throws Exception {
File fileMock = PowerMock.createMock(File.class);
PersistenceManager tested = new PersistenceManager();
PowerMock.expectNew(File.class, "directoryPath").andReturn(fileMock);
EasyMock.expect(fileMock.exists()).andReturn(false);
EasyMock.expect(fileMock.mkdirs()).andReturn(true);
PowerMock.replay(fileMock, File.class);
assertTrue(tested.createDirectoryStructure("directoryPath"));
PowerMock.verify(fileMock, File.class);
}
}
也可以使用更简便的方法:
FilefileMock = PowerMock.createMockAndExpectNew(File.class,“directoryPath”);
通过EasyMock+PowerMock,开发中绝大部分的方法都可以被测试完全覆盖。
更多关于PowerMock的用法和参考文档请参考PowerMock官方网址:
https://code.google.com/p/powermock/。
如果遇到了静态、final类型的类和方法,以及私有方法,EasyMock的动态代理局限性使得无法测试这些特性情况。
PowerMock是在EasyMock基础上进行扩展(只是补充,不是替代),使用了字节码操作技术直接对生成的字节码类文件进行修改,从而可以方便对静态,final类型的类和方法进行Mock,还可以对私有方法进行Mock,更可以对类进行部分Mock。
PowerMock的工作过程和EasyMock类似,不同之处在于需要在类层次声明@RunWith(PowerMockRunner.class)注解,以确保使用PowerMock框架引擎执行单元测试。
通过如下方式在maven添加PowerMock相关依赖:
[html] view plain copy
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-easymock</artifactId>
<version>1.5.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.5.1</version>
<scope>test</scope>
</dependency>
例子如下:
(1).Miock final类的静态方法:
如果测试代码中使用到了java.lang.System类,代码如下:
[java] view plain copy
public class SystemPropertyMockDemo {
public String getSystemProperty() throws IOException {
return System.getProperty("property");
}
}
如果对System.getProperty()方法进行Mock,代码如下:
[java] view plain copy
@RunWith(PowerMockRunner.class)
@PrepareForTest({SystemPropertyMockDemo.class})//声明要Mock的类
public class SystemPropertyMockDemoTest {
@Test
public void demoOfFinalSystemClassMocking() throws Exception {
PowerMock.mockStatic(System.class);//Mock静态方法
EasyMock.expect(System.getProperty("property")).andReturn("my property");//录制Mock对象的静态方法
PowerMock.replayAll();//重放Mock对象
Assert.assertEquals("my property",
new SystemPropertyMockDemo().getSystemProperty());
PowerMock.verifyAll();//验证Mock对象
}
}
非final类的静态方法代码相同,注意(上述代码只能在EasyMock3.0之后版本正常运行)
如果要在EasyMock3.0之前版本正常Mock final类的静态方法,需要使用PowerMockito,
通过如下方式在maven中添加PowerMockito相关依赖:
[html] view plain copy
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.5.1</version>
<scope>test</scope>
</dependency>
代码如下:
[java] view plain copy
@RunWith(PowerMockRunner.class)
@PrepareForTest({SystemPropertyMockDemo.class})
public class SystemPropertyMockDemoTest {
@Test
public void demoOfFinalSystemClassMocking() throws Exception {
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getProperty("property")).thenReturn("my property");
PowerMock.replayAll();
Assert.assertEquals("my property",
new SystemPropertyMockDemo().getSystemProperty());
PowerMock.verifyAll();
}
}
注意:
对于JDK的类如果要进行静态或final方法Mock时,@PrepareForTest()注解中只能放被测试的类,而非JDK的类,如上面例子中的SystemPropertyMockDemo.class。
对于非JDK的类如果需要进行静态活final方法Mock时, @PrepareForTest()注解中直接放方法所在的类,若上面例子中的System不是JDK的类,则可以直接放System.class。
@PrepareForTest({......}) 注解既可以加在类层次上(对整个测试文件有效),也可以加在测试方法上(只对测试方法有效)。
(2).Mock非静态的final方法:
被测试代码如下:
[java] view plain copy
public class ClassDependency {
public final boolean isAlive() {
return false;
}
}
public class ClassUnderTest{
public boolean callFinalMethod(ClassDependency refer) {
return refer.isAlive();
}
}
使用PowerMock的测试代码如下:
[java] view plain copy
@RunWith(PowerMockRunner.class)
public class FinalMethodMockDemoTest {
@Test
@PrepareForTest(ClassDependency.class)
public void testCallFinalMethod() {
ClassDependency depencency = PowerMock.createMock(ClassDependency.class); //创建Mock对象
ClassUnderTest underTest = new ClassUnderTest();
EasyMock.expect(depencency.isAlive()).andReturn(true);
PowerMock.replayAll();
Assert.assertTrue(underTest.callFinalMethod(depencency));
PowerMock.verifyAll();
}
}
(3)部分Mock和私有方法Mock:
如果被测试类某个方法不太容易调用,可以考虑只对该方法进行Mock,而其他方法全部使用被测试对象的真实方法,可以考虑使用PowerMock的部分Mock,被测试代码如下:
[java] view plain copy
public class DataService {
public boolean replaceData(final String dataId, final byte[] binaryData) {
return modifyData(dataId, binaryData);
}
public boolean deleteData(final String dataId) {
return modifyData(dataId, null);
}
private boolean modifyData(final String dataId, final byte[] binaryData) {
return true;
}
}
只对modifyData方法进行Mock,而其他方法调用真实方法,测试代码如下:
[java] view plain copy
@RunWith(PowerMockRunner.class)
@PrepareForTest(DataService.class)
public class DataServiceTest {
@Test
public void testReplaceData() throws Exception {
DataService tested = PowerMock.createPartialMock(DataService.class, “modifyData”);//创建部分mock对象,只对modifyData方法Mock
PowerMock.expectPrivate(tested, “modifyData”, “id”, null).andReturn(true);//录制私有方法
PowerMock.replay(tested);
assertTrue(tested.deleteData(“id”));
PowerMock.verify(tested);
}
}
部分Mock在被测试方法的依赖在同一个类,且不容易创建时比较有用。
个人认为私有方法的Mock意义不是很大,完全可以使用反射机制直接调用。
(4).调用对象的构造方法Mock对象:
在被测试方法内部调用构造创建了一个对象很常见,被测试代码如下:
[java] view plain copy
public class PersistenceManager {
public boolean createDirectoryStructure(String directoryPath) {
File directory = new File(directoryPath);
if (directory.exists()) {
throw new IllegalArgumentException("\"" + directoryPath + "\" already exists.");
}
return directory.mkdirs();
}
}
创建文件操作(new File(path))依赖与操作系统底层实现,如果给定的路径不合法,将会出现异常导致测试无法正常覆盖,此时需要使用PowerMock的提供的调用构造方法创建Mock对象,测试代码如下:
[java] view plain copy
@RunWith(PowerMockRunner.class)
@PrepareForTest( PersistenceManager.class )
public class PersistenceManagerTest {
@Test
public void testCreateDirectoryStructure_ok() throws Exception {
File fileMock = PowerMock.createMock(File.class);
PersistenceManager tested = new PersistenceManager();
PowerMock.expectNew(File.class, "directoryPath").andReturn(fileMock);
EasyMock.expect(fileMock.exists()).andReturn(false);
EasyMock.expect(fileMock.mkdirs()).andReturn(true);
PowerMock.replay(fileMock, File.class);
assertTrue(tested.createDirectoryStructure("directoryPath"));
PowerMock.verify(fileMock, File.class);
}
}
也可以使用更简便的方法:
FilefileMock = PowerMock.createMockAndExpectNew(File.class,“directoryPath”);
通过EasyMock+PowerMock,开发中绝大部分的方法都可以被测试完全覆盖。
更多关于PowerMock的用法和参考文档请参考PowerMock官方网址:
https://code.google.com/p/powermock/。
相关文章推荐
- SNFAutoupdater通用自动升级组件V2.0
- ios中写framework并调用的方法以及所遇到的问题
- 最少拦截系统
- [fzu2016]How many tuples 解题报告
- bnuoj_20924 Permutations
- 相对路径的获取拼接
- OpenSSL - 利用OpenSSL自签证书和CA颁发证书
- 网络库crash以及boost asio strand dispath分析
- __stdcall,__cdecl,__fastcall的区别
- 在Xcode中使用Git进行源码版本控制
- Android 通过JNI实现守护进程,使Service服务不被杀死
- ACM中的博弈论入门(二) POJ 2960 SG 函数的应用
- xstream 别名的用法
- Length of Last Word
- _fastcall
- 【Android】SQLite 数据库基本操作
- 关于两个php.ini的说明
- Centos6.5 python升级成2.7版本出现的一些问题解决方法
- PNP型三极管____本人备注
- 声学