Java单元测试--基于Mockito的PowerMock使用

本文详细介绍如何使用基于Mockito的PowerMock进行单元测试,包括mock非静态方法、静态方法、部分方法、void方法、父类方法及私有方法等。通过实际代码示例,帮助读者快速掌握PowerMock的使用技巧。

Powermock 扩展于EasyMock和Mockito,而Mockito相对于EasyMock的优点其中一个是异常更清晰易懂。

 

现在用的是基于Mockito的Powermock,它可以mock静态方法,mock构造函数,mock void方法,mock部分方法,mock私有方法等。以下是如果使用基于Mockito的Powermock版本。

 

1.导入包

 其中 <powermock.version>1.6.3</powermock.version>

        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-module-junit4</artifactId>
            <version>${powermock.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-api-easymock</artifactId>
            <version>${powermock.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency> 
            <groupId>org.powermock</groupId> 
            <artifactId>powermock-api-mockito</artifactId> 
            <version>${powermock.version}</version> 
            <scope>test</scope> 
        </dependency>

 

假设我们需要测试下面的Hello类

 

class Hi {
    public void mockParentMethod() {
        System.out.println("mockSuperMethod Hi");
    }
}

class Hello extends Hi {
    private Kitty kitty;

    public Hello() {}
    
    public void mockParentMethod() {
        super.mockParentMethod();        
        System.out.println("mockParentMethod Hello");
    }
    public void mockNonStaticMethod() {
        String name = kitty.getName();
        System.out.println("mockNonStaticMethod" + name);
    }
    
    public void mockStaticMethod() {
        String name = Kitty.getName2();
        System.out.println("mockStaticMethod" + name);
    }
    
    public void partialMock() {
        _partialMock();
        System.out.println("partialMock");
    }

    private void _partialMock() {
        System.out.println("method3");
    }
    
    public void mockVoidMethod() {
        kitty.say3();
        System.out.println("partialMock");
    }

    public Kitty getKitty() {
        return kitty;
    }

    public void setKitty(Kitty kitty) {
        this.kitty = kitty;
    }
    
}

class Kitty {
    public String getName() {
        return "Kitty";
    }
    
    public static String getName2() {
        return "Kitty";
    }
    
    public void say3() {
        System.out.println("say3");
    }
}

 

 

2. 导入声明

测试类时,要导入以下声明:

 

@RunWith(PowerMockRunner.class)
public class HelloTest {
}

 

 

3. 测试方法

3.1 mock 非静态方法

 

    @Test
    public void testMockNonStaticMethod() {
        Hello hello = new Hello();
        Kitty kitty = PowerMockito.mock(Kitty.class);
        hello.setKitty(kitty);
        PowerMockito.when(kitty.getName()).thenReturn("test");
        hello.mockNonStaticMethod();
    }

 

 

3.2 mock 静态方法

首先需要PrepareForTest导入静态方法的类

 

@RunWith(PowerMockRunner.class)
@PrepareForTest({Kitty.class})
class HelloTest {
    @Test
    public void testMockStaticMethod() {
        Hello hello = new Hello();
        PowerMockito.mockStatic(Kitty.class);
        PowerMockito.when(Kitty.getName2()).thenReturn("test");
        hello.mockStaticMethod();
    }
}

 

 

3.3 partial mock (mock 部分方法)

如果只想mock一个类里面的个别方法,可以使用spy方法

 

@RunWith(PowerMockRunner.class)
@PrepareForTest({Hello.class})
public class HelloTest {
    @Test
    public void testPartialMock() {
        Hello hello = PowerMockito.spy(new Hello());
        try {
            PowerMockito.doReturn("test").when(hello, MemberMatcher.method(Hello.class, "_partialMock")).withNoArguments();
        } catch (Exception e) {
            e.printStackTrace();
        }
        hello.partialMock();
    }
}

 

 

3.4 mock void 方法

 

    @Test
    public void testMockVoidMethod() {
        Hello hello = new Hello();
        Kitty kitty = PowerMockito.mock(Kitty.class);
        hello.setKitty(kitty);
        PowerMockito.doNothing().when(kitty).say3();
        hello.mockVoidMethod();
    }

 

 3.5 mock parent method (父类方法)

使用PowerMockito.suppress()方法

 

    @Test
    public void testMockParentMethod() {
        Hello hello = new Hello();
        PowerMockito.suppress(MemberMatcher.methodsDeclaredIn(Hi.class));
        hello.testMockParentMethod();
    }

 不过这个版本好像有个bug,如果用了spy mock 子类,当子类方法里面调了父类的两次(或以上)相同或者不相同的方法时,测试子类的方法会报StackOverflowError异常,如下面的子类方法:

public void mockParentMethod() {
        super.mockParentMethod();       //一次 
        System.out.println("mockParentMethod Hello");
        super.mockParentMethod();       //两次
    }

@Test
    public void testMockParentMethod() {
        Hello hello = PowerMockito.spy(new Hello());
        PowerMockito.suppress(MemberMatcher.methodsDeclaredIn(Hi.class));
        hello.testMockParentMethod();    // throw StackOverflowError exception
    }

 

3.6 测试私有方法

格式: PowerMockito.verifyPrivate(objectOrClassToInvoke).invoke("methodToBeTest", parms);

public void testPrivateMethod() {
	Hello hello = new  Hello();
	PowerMockito.verifyPrivate(hello).invoke("_partialMock");
}

 

或者使用 WhiteBox.invokeMethod() 方法。

 

 3.6 mock构造函数

使用 PowerMockito.whenNew() 方法

 

Hello hello = PowerMockito.mock(Hello.class)
PowerMockito.whenNew(Hello.class).thenReturn(hello);

 

 

 

 相关链接

powermock官网:https://github.com/jayway/powermock

 

### 解决Mockito Inline与PowerMock兼容性问题 当尝试将Mockito Inline(即`mock-maker-inline`模块)与PowerMock结合使用时,可能会遇到一些兼容性和类加载方面的问题。为了确保两者能够顺利协作,建议遵循以下策略: #### 版本匹配 确保所使用MockitoPowerMock版本相互兼容至关重要。对于较新的Mockito版本(特别是引入了`mock-maker-inline`特性的那些),应当选择对应适配的PowerMock版本[^3]。 例如,在某些情况下,如果正在使用Mockito 2.x,则应考虑采用PowerMock 1.7以上的版本来获得更好的支持。 #### 配置依赖项 在项目构建工具配置文件中(如Maven或Gradle),显式指定所需的库及其版本号可以帮助避免潜在冲突。以下是基于Maven的一个可能设置方式: ```xml <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>2.28.2</version> <scope>test</scope> </dependency> <!-- For mocking static methods --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-inline</artifactId> <version>2.28.2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>2.0.9</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito2</artifactId> <version>2.0.9</version> <scope>test</scope> </dependency> ``` 注意这里选择了Mockito 2.28.2以及相适应的PowerMock 2.0.9版本组合。 #### 处理特定异常 针对提到的具体错误`java.lang.NoClassDefFoundError: org/mockito/exceptions/base/Reporter`,这通常意味着存在类路径上的缺失或者是不同版本之间的二进制不兼容情况。通过更新至最新稳定版并保持一致的依赖关系可以有效缓解此类问题[^4]。 另外,考虑到PowerMockJava Agent的支持需求,确保JVM启动参数包含了必要的代理选项也是解决问题的关键之一。可以在运行测试之前添加如下命令行参数: ``` -javaagent:path/to/org.powermock.modules.agent.PowerMockAgent.jar ``` 以上措施有助于改善Mockito Inline同PowerMock共同工作时的表现,并减少可能出现的技术障碍。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值