欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

PowerMock使用分享 单元测试mockpowermockjava 

程序员文章站 2024-01-31 18:31:10
...
单元测试是对应用中的某一个模块的功能进行验证。在单元测试中,我们常遇到的问题是依赖的模块尚未开发完成或者被测试模块需要和一些不容易构造、比较复杂的对象进行交互。另外,由于不能肯定其它模块的正确性,我们也无法确定测试中发现的问题是由哪个模块引起的。所谓的mock,就是指,如果我们写的代码依赖于某些对象,而这些对象又很难手动创建,那么就使用一个虚拟的对象来完成单元测试。在java界现在比较流行的mock工具有:
jMock: http://jmock.org/
EasyMock: http://easymock.org/
Mockito: http://code.google.com/p/mockito/
但是这些mock工具都有一些缺陷,就是不能mock静态、final、私有方法等,而powermock能够做到。
Power Mock:http://code.google.com/p/powermock/
Power Mock有两个版本,一个是基于easymock实现的,另一个是基于mockito实现的。

备注:如果你使用JaCoCo作为你的code coverage插件的话,那么所有写在注解@PrepareForTest里的类的覆盖率都是零。这是JaCoCo插件的限制或者说是Bug:https://github.com/jacoco/eclemma/issues/15,而且它并不打算修改这个Bug。所以如果你想使用PowerMock提升覆盖率的话,请使用其它的code coverage插件:cobertura
Sonar里默认的code coverage插件是JaCoCo。


下面我将以Power Mock的mockito的版本来讲述如何使用Power Mock。
测试目标类:
public class ClassUnderTest {

    public boolean callArgumentInstance(File file) {
        return file.exists();
    }
    
    public boolean callInternalInstance(String path) {
        File file = new File(path);
        return file.exists();
    }
    
    public boolean callFinalMethod(ClassDependency refer) {
        return refer.isAlive();
    }
    
    public boolean callSystemFinalMethod(String str) {
        return str.isEmpty();
    }
    
    public boolean callStaticMethod() {
        return ClassDependency.isExist();
    }
    
    public String callSystemStaticMethod(String str) {
        return System.getProperty(str);
    }
    
    public boolean callPrivateMethod() {
        return isExist();
    }
    
    private boolean isExist() {
        // do something
        return false;
    }
}

依赖类:
public class ClassDependency {

    public static boolean isExist() {
        // do something
        return false;
    }
    
    public final boolean isAlive() {
        // do something
        return false;
    }
}


接下来,对6个测试用例进行逐个的讲解。
首先需要使用@RunWith(PowerMockRunner.class)将测试用例的runner改为PowerMockRunner
1、testCallArgumentInstance:Mock参数传递的对象
    @Test
    public void testCallArgumentInstance() {
        File file = PowerMockito.mock(File.class);
        ClassUnderTest underTest = new ClassUnderTest();
        PowerMockito.when(file.exists()).thenReturn(true);
        Assert.assertTrue(underTest.callArgumentInstance(file));
    }

需要mock的对象是由参数传进去的,这是最普通的一种mock方式,jMock,EasyMock,Mockito都能实现。
步骤:
a、通过PowerMockito.mock(File.class)创建出一个mock对象
b、然后再通过PowerMockito.when(file.exists()).thenReturn(false);来指定这个mock对象具体的行为
c、再将mock对象作为参数传递个测试方法,执行测试方法。

2、testCallInternalInstance:Mock方法内部new出来的对象
    @Test
    @PrepareForTest(ClassUnderTest.class)
    public void testCallInternalInstance() throws Exception {
        File file = PowerMockito.mock(File.class);
        ClassUnderTest underTest = new ClassUnderTest();
        PowerMockito.whenNew(File.class).withArguments("bbb").thenReturn(file);
        PowerMockito.when(file.exists()).thenReturn(true);
        Assert.assertTrue(underTest.callInternalInstance("bbb"));
    }

需要mock的对象是在方法内部new出来的,这是一种比较常见的mock方式。
步骤(已经讲过的步骤省略):
a、通过PowerMockito.whenNew(File.class).withArguments("bbb").thenReturn(file)来指定当以参数为bbb创建File对象的时候,返回已经mock的File对象。
b、在测试方法之上加注解@PrepareForTest(ClassUnderTest.class),注解里写的类是需要mock的new对象代码所在的类。

3、testCallFinalMethod:Mock普通对象的final方法。
    @Test
    @PrepareForTest(ClassDependency.class)
    public void testCallFinalMethod() {
        
        ClassDependency depencency = PowerMockito.mock(ClassDependency.class);
        ClassUnderTest underTest = new ClassUnderTest();
        PowerMockito.when(depencency.isAlive()).thenReturn(true);
        Assert.assertTrue(underTest.callFinalMethod(depencency));
    }

Mock的步骤和之前的一样,只是需要在测试方法之上加注解@PrepareForTest(ClassDependency.class),注解里写的类是需要mock的final方法所在的类。

4、testCallStaticMethod:Mock静态方法。
    @Test
    @PrepareForTest(ClassDependency.class)
    public void testCallStaticMethod() {
        ClassUnderTest underTest = new ClassUnderTest();
        PowerMockito.mockStatic(ClassDependency.class);
        PowerMockito.when(ClassDependency.isExist()).thenReturn(true);
        Assert.assertTrue(underTest.callStaticMethod());
    }

步骤:
a、通过PowerMockito.mockStatic(ClassDependency.class);表示需要mock这个类里的静态方法
b、在测试方法之上加注解@PrepareForTest(ClassDependency.class),注解里写的类是需要mock的静态方法所在的类。

5、testCallSystemStaticMethod:Mock JDK中类的静态方法。
   testCallSystemFinalMethod:Mock JDK对象的final方法。

 
  @Test
    @PrepareForTest(ClassUnderTest.class)
    public void testCallSystemStaticMethod() {
        ClassUnderTest underTest = new ClassUnderTest();
        PowerMockito.mockStatic(System.class);
        PowerMockito.when(System.getProperty("aaa")).thenReturn("bbb");
        Assert.assertEquals("bbb", underTest.callJDKStaticMethod("aaa"));
    }

    @Test
    @PrepareForTest(ClassUnderTest.class)
    public void testCallSystemFinalMethod() {
        
        String str = PowerMockito.mock(String.class);
        ClassUnderTest underTest = new ClassUnderTest();
        PowerMockito.when(str.isEmpty()).thenReturn(false);
        Assert.assertFalse(underTest.callJDKFinalMethod(str));
    }

和Mock普通对象的静态方法、final方法一样,只不过注解里写的类不一样@PrepareForTest(ClassUnderTest.class),注解里写的类是需要调用系统方法所在的类。

6、testCallPrivateMethod:Mock私有方法。
    @Test
    @PrepareForTest(ClassUnderTest.class)
    public void testCallPrivateMethod() throws Exception {
        ClassUnderTest underTest = PowerMockito.mock(ClassUnderTest.class);
        PowerMockito.when(underTest.callPrivateMethod()).thenCallRealMethod();
        PowerMockito.when(underTest, "isExist").thenReturn(true);
        Assert.assertTrue(underTest.callPrivateMethod());
    }

和Mock普通方法一样,只是需要加注解@PrepareForTest(ClassUnderTest.class),注解里写的类是私有方法所在的类。

完整的测试用例类:
@RunWith(PowerMockRunner.class)
public class TestClassUnderTest {

    @Test
    public void testCallArgumentInstance() {
        File file = PowerMockito.mock(File.class);
        ClassUnderTest underTest = new ClassUnderTest();
        PowerMockito.when(file.exists()).thenReturn(true);
        Assert.assertTrue(underTest.callArgumentInstance(file));
    }
    
    @Test
    @PrepareForTest(ClassUnderTest.class)
    public void testCallInternalInstance() throws Exception {
        File file = PowerMockito.mock(File.class);
        ClassUnderTest underTest = new ClassUnderTest();
        PowerMockito.whenNew(File.class).withArguments("bbb").thenReturn(file);
        PowerMockito.when(file.exists()).thenReturn(true);
        Assert.assertTrue(underTest.callInternalInstance("bbb"));
    }
    
    @Test
    @PrepareForTest(ClassDependency.class)
    public void testCallFinalMethod() {
        
        ClassDependency depencency = PowerMockito.mock(ClassDependency.class);
        ClassUnderTest underTest = new ClassUnderTest();
        PowerMockito.when(depencency.isAlive()).thenReturn(true);
        Assert.assertTrue(underTest.callFinalMethod(depencency));
    }
    
    @Test
    @PrepareForTest(ClassUnderTest.class)
    public void testCallSystemFinalMethod() {
        
        String str = PowerMockito.mock(String.class);
        ClassUnderTest underTest = new ClassUnderTest();
        PowerMockito.when(str.isEmpty()).thenReturn(false);
        Assert.assertFalse(underTest.callSystemFinalMethod(str));
    }
    
    @Test
    @PrepareForTest(ClassDependency.class)
    public void testCallStaticMethod() {
        ClassUnderTest underTest = new ClassUnderTest();
        PowerMockito.mockStatic(ClassDependency.class);
        PowerMockito.when(ClassDependency.isExist()).thenReturn(true);
        Assert.assertTrue(underTest.callStaticMethod());
    }
    
    @Test
    @PrepareForTest(ClassUnderTest.class)
    public void testCallSystemStaticMethod() {
        ClassUnderTest underTest = new ClassUnderTest();
        PowerMockito.mockStatic(System.class);
        PowerMockito.when(System.getProperty("aaa")).thenReturn("bbb");
        Assert.assertEquals("bbb", underTest.callSystemStaticMethod("aaa"));
    }
    
    @Test
    @PrepareForTest(ClassUnderTest.class)
    public void testCallPrivateMethod() throws Exception {
        ClassUnderTest underTest = PowerMockito.mock(ClassUnderTest.class);
        PowerMockito.when(underTest.callPrivateMethod()).thenCallRealMethod();
        PowerMockito.when(underTest, "isExist").thenReturn(true);
        Assert.assertTrue(underTest.callPrivateMethod());
    }
}