PowerMockito的基本使用记录

本文记录了使用PowerMockito进行单元测试的过程,通过它能够对private方法和static工具类进行模拟,解决传统Mock工具的限制。内容涵盖基本mock设置、静态方法的模拟以及多次调用返回不同值的场景,帮助提升测试覆盖率。

Mock是编程中Unit测试的常态。最开始使用的是easymock,确实很easy,可惜功能不够强大。对于private方法测试无能为力,对于static的工具类也没有办法,于是转向了PowerMockito,很好的解决了我的困扰。


Mock测试的主要做法就是在真实方法调用之前先模拟被测试类关联的外部类,接口的调用实现,对指定的参数,返回虚拟的结果(虚拟的返回值或者异常等),然后调用测试方法,再之后验证模拟的函数调用都有发生。


记录一下我使用powermockito的一些测试用例。


1.基本简单的mock和验证 (被测试的类是JcifsDataTransfer,引用的类包括NtlmPasswordAuthentication和SmbFile),其中NtlmPasswordAuthentication和SmbFile是在被测试类中New的实例,所以需要在Class的annotation中除了@RunWith(PowerMockRunner.class) 也要加入 @preparefortest (JcifsDataTransfer.class)。方法调用都是有返回值的,所以用when.thenReturn来模拟。

注意:New的preparefortest必须是被测试类

好的!下面是使用 **JUnit4 + Mockito + PowerMockito** 来对 `AdbUtil.execCommand()` 方法进行单元测试的完整示例,**重点是使用 PowerMockito 模拟 `Runtime.getRuntime().exec()` 这个静态方法。** --- ### ✅ 依赖配置(`build.gradle`) 确保你的测试依赖中包含 JUnit4、Mockito 和 PowerMockito: ```gradle testImplementation 'junit:junit:4.13.2' testImplementation 'org.mockito:mockito-core:3.12.4' testImplementation 'org.powermock:powermock-module-junit4:2.0.9' testImplementation 'org.powermock:powermock-api-mockito2:2.0.9' ``` --- ### ✅ 使用 PowerMockito mock `Runtime.getRuntime().exec()` ```java package com.st.base.utils; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import static org.junit.Assert.*; import static org.mockito.Mockito.*; @RunWith(PowerMockRunner.class) @PrepareForTest({Runtime.class, AdbUtil.class}) public class AdbUtilTest { private Process mockProcess; private BufferedReader mockInputStreamReader; private BufferedReader mockErrorStreamReader; @Before public void setUp() throws Exception { mockProcess = mock(Process.class); mockInputStreamReader = mock(BufferedReader.class); mockErrorStreamReader = mock(BufferedReader.class); } @Test public void testExecCommand_FindsPrefixInOutput() throws Exception { // 模拟输入流中包含 prefix 的情况 when(mockInputStreamReader.readLine()) .thenReturn("Some text topResumedActivityPackageName=com.example.app other text") .thenReturn(null); // 读取完一行后返回 null 表示结束 when(mockProcess.getInputStream()).thenReturn(newInputStream("test")); when(mockProcess.getErrorStream()).thenReturn(newInputStream("")); when(mockProcess.waitFor()).thenReturn(0); // 使用 PowerMockito 模拟 Runtime.getRuntime().exec PowerMockito.mockStatic(Runtime.class); when(Runtime.getRuntime().exec("test-command")).thenReturn(mockProcess); // 调用被测试方法 String result = AdbUtil.execCommand("test-command"); // 验证是否正确截取 assertTrue(result.contains("topResumedActivityPackageName=com.example.app")); } @Test public void testExecCommand_NoMatch_ReturnsEmpty() throws Exception { when(mockInputStreamReader.readLine()).thenReturn("Some random output without prefix").thenReturn(null); when(mockProcess.getInputStream()).thenReturn(newInputStream("test")); when(mockProcess.getErrorStream()).thenReturn(newInputStream("")); when(mockProcess.waitFor()).thenReturn(0); PowerMockito.mockStatic(Runtime.class); when(Runtime.getRuntime().exec("test-command")).thenReturn(mockProcess); String result = AdbUtil.execCommand("test-command"); assertEquals("", result); } @Test public void testExecCommand_ReadsErrorStream() throws Exception { when(mockInputStreamReader.readLine()).thenReturn(null); // 没有输出 when(mockErrorStreamReader.readLine()).thenReturn("Error occurred").thenReturn(null); when(mockProcess.getInputStream()).thenReturn(newInputStream("")); when(mockProcess.getErrorStream()).thenReturn(newInputStream("Error occurred")); when(mockProcess.waitFor()).thenReturn(1); // 模拟失败 PowerMockito.mockStatic(Runtime.class); when(Runtime.getRuntime().exec("test-command")).thenReturn(mockProcess); String result = AdbUtil.execCommand("test-command"); assertEquals("", result); } private InputStream newInputStream(String content) { return new java.io.ByteArrayInputStream(content.getBytes()); } @After public void tearDown() { mockProcess = null; mockInputStreamReader = null; mockErrorStreamReader = null; } } ``` --- ### ✅ 说明 - `@RunWith(PowerMockRunner.class)`:使用 PowerMock 的运行器。 - `@PrepareForTest({Runtime.class, AdbUtil.class})`:准备 mock 静态类(Runtime)和目标类(AdbUtil)。 - `PowerMockito.mockStatic(Runtime.class)`:mock 静态类 `Runtime`。 - `when(Runtime.getRuntime().exec("test-command")).thenReturn(mockProcess)`:模拟 `exec` 方法返回 mock 的 `Process`。 - `newInputStream(...)`:辅助方法用于创建模拟的 `InputStream`。 --- ### ✅ 重构建议 虽然 PowerMockito 能够 mock 静态方法,但它会让测试变得复杂且不易维护。**更推荐重构 `AdbUtil`,将 `Runtime.exec` 封装为可注入的接口,以提升可测试性。** --- ### ✅ 总结 通过 PowerMockito 可以成功 mock `Runtime.getRuntime().exec()`,并模拟 `Process` 和 `BufferedReader`,从而对 `AdbUtil.execCommand()` 进行完整的单元测试。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值