使用Powermock工具mock系统类(java.util.Date的构造方法)

本文介绍如何使用PowerMock和Mockito工具组合,针对java.util.Date类的构造函数进行mock操作,确保DateFormat类中formatCurrentTime方法返回的当前时间格式化字符串与直接调用SIMPLE_DATE_FORMAT格式化方法的结果一致。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

场景

示例,有如下DateFormat的formatCurrentTime()方法,代码如下:

public class DateFormat {

    public static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyMMddHHmmssZ");

    public static String formatCurrentTime() {
        return SIMPLE_DATE_FORMAT.format(new Date());
    }
}

我现在期望判断formatCurrentTime方法返回的值是否是SIMPLE_DATE_FORMAT对象格式化的值(当然了,这代码一看肯定是了,不要觉得这没意义,实际工作中真的有类似无聊而又什么什么的需求)。

为了满足这个要求,我只需要判断SIMPLE_DATE_FORMAT.format(new Date())是否等于DateFormat.formatCurrnetTime()方法调用的返回值就行了。但是很明显,formatCurrnetTime方法内部调用SIMPLE_DATE_FORMAT.format方法时传入的参数直接new了一个Date对象,我外部显式调用SIMPLE_DATE_FORMAT.format方法的时候又再创建的Date对象肯定不是这一个了,所以我需要mock java.util.Date类的无参构造方法,保证每次new的时候返回的是同一个对象。

测试代码如下:

实现

@RunWith(PowerMockRunner.class)
@PrepareForTest(DateFormat.class)
public class DateFormatTest {

    @Before
    public void setup() {
        PowerMockito.mockStatic(Date.class);
    }

    @Test
    public void testFormatCurrentTime() throws Exception {
        Date date = new Date();
        PowerMockito.whenNew(Date.class).withNoArguments().thenReturn(date);
        Assert.assertEquals(DateFormat.SIMPLE_DATE_FORMAT.format(date), DateFormat.formatCurrentTime());
    }
}

如上代码:

说明下对于java.util.Date类这种JDK的类的mock操作过程,这里使用Powermock,关于Powermock的配置可以看Mockito配合powermock工具mock构造函数这篇文章。

步骤如下:

1. 测试类上使用注解@RunWith(PowerMockRunner.class)

2. 注解@PrepareForTest声明调用系统类的类:上面自己定义的DateFormat类

3. 调用mockStatic方法mock Date类(调用PowerMockito的mock方法也可以,毕竟这里需求只是mock 构造方法,我使用mockStatic,是因为看了它的维基上的介绍,地址在这:https://github.com/powermock/powermock/wiki/Mock-System)。

最后根据这里的需要设置Date的无参构造方法的期望返回值,mock构造方法的api使用可以看Mockito配合powermock工具mock构造函数这篇文章了解下。

package com.st.systemsettings.manager; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockedStatic; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import android.content.Context; import android.util.Log; import java.lang.reflect.Field; import java.util.concurrent.CountDownLatch; import static org.junit.Assert.*; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.*; @RunWith(PowerMockRunner.class) @PrepareForTest({Log.class, OptixDisplayManager.class}) public class PictureManagerTest { @Mock private Context mockContext; @Mock private PictureManager.PictureModeChangedListener mockListener; @Mock private OptixDisplayManager mockOptixDisplayManager; private PictureManager pictureManager; @Before public void setUp() { try { // 初始化 Mockito 注解 MockitoAnnotations.openMocks(this); // 准备静态模拟 prepareStaticMocks(); // 重置单例状态 resetSingleton(); // 创建实例并初始化 pictureManager = PictureManager.getInstance(); pictureManager.init(mockContext); // 注入模拟的 OptixDisplayManager injectMockOptixDisplayManager(); // 设置模拟监听器 pictureManager.setPictureModeChangedListener(mockListener); } catch (Exception e) { throw new RuntimeException("Setup failed", e); } } @After public void tearDown() { try { resetSingleton(); } catch (Exception e) { // 安全地忽略清理错误 } } // 准备静态模拟 private void prepareStaticMocks() { // 模拟 Log PowerMockito.mockStatic(Log.class); PowerMockito.when(Log.i(anyString(), anyString())).thenReturn(0); // 模拟 OptixDisplayManager 的单例 PowerMockito.mockStatic(OptixDisplayManager.class); PowerMockito.when(OptixDisplayManager.getInstance()).thenReturn(mockOptixDisplayManager); } // 修复后的重置单例方法 - 不再抛出受检异常 private void resetSingleton() { try { Field instanceField = PictureManager.class.getDeclaredField("sManager"); instanceField.setAccessible(true); instanceField.set(null, null); } catch (Exception e) { // 将受检异常转换为运行时异常 throw new RuntimeException("Failed to reset singleton", e); } } // 修复后的注入方法 - 不再抛出受检异常 private void injectMockOptixDisplayManager() { try { Field optixField = PictureManager.class.getDeclaredField("mOptixDisplayManager"); optixField.setAccessible(true); optixField.set(pictureManager, mockOptixDisplayManager); } catch (Exception e) { throw new RuntimeException("Failed to inject mock", e); } } @Test public void testSingletonPattern() { PictureManager firstInstance = PictureManager.getInstance(); PictureManager secondInstance = PictureManager.getInstance(); assertSame(firstInstance, secondInstance); } @Test public void testInitSetsContextCorrectly() { try { Field contextField = PictureManager.class.getDeclaredField("mContext"); contextField.setAccessible(true); Context privateContext = (Context) contextField.get(pictureManager); assertSame(mockContext, privateContext); } catch (Exception e) { fail("Reflection failed: " + e.getMessage()); } } @Test public void testSetPictureModeCallsOptixManager() { int testMode = 2; pictureManager.setPictureMode(testMode); verify(mockOptixDisplayManager).setCanvasSize(testMode); } @Test public void testSetPictureModeTriggersListener() { int testMode = 3; pictureManager.setPictureMode(testMode); verify(mockListener).onPictureModeChanged(testMode); } @Test public void testSetPictureModeWithoutListener() { pictureManager.setPictureModeChangedListener(null); int testMode = 4; pictureManager.setPictureMode(testMode); verify(mockListener, never()).onPictureModeChanged(anyInt()); } @Test public void testGetPictureModeReturnsCorrectValue() { int expectedMode = 5; when(mockOptixDisplayManager.getCanvasSize()).thenReturn(expectedMode); int result = pictureManager.getPictureMode(); assertEquals(expectedMode, result); } @Test public void testListenerIsSetCorrectly() { PictureManager.PictureModeChangedListener newListener = mock(PictureManager.PictureModeChangedListener.class); pictureManager.setPictureModeChangedListener(newListener); pictureManager.setPictureMode(1); verify(newListener).onPictureModeChanged(1); verify(mockListener, never()).onPictureModeChanged(anyInt()); } @Test public void testReInitUpdatesContext() { try { Context newContext = Mockito.mock(Context.class); pictureManager.init(newContext); Field contextField = PictureManager.class.getDeclaredField("mContext"); contextField.setAccessible(true); Context privateContext = (Context) contextField.get(pictureManager); assertSame(newContext, privateContext); } catch (Exception e) { fail("Reflection failed: " + e.getMessage()); } } @Test public void testThreadSafety() throws InterruptedException { resetSingleton(); // 现在安全了 CountDownLatch latch = new CountDownLatch(2); PictureManager[] instances = new PictureManager[2]; Thread t1 = new Thread(() -> { instances[0] = PictureManager.getInstance(); latch.countDown(); }); Thread t2 = new Thread(() -> { instances[1] = PictureManager.getInstance(); latch.countDown(); }); t1.start(); t2.start(); latch.await(); assertNotNull(instances[0]); assertSame(instances[0], instances[1]); } @Test public void testLoggingInSetPictureMode() { int testMode = 6; pictureManager.setPictureMode(testMode); PowerMockito.verifyStatic(Log.class); Log.i("PictureManager", "setPictureMode: mode = " + testMode); } @Test public void testLoggingInGetPictureMode() { int expectedMode = 7; when(mockOptixDisplayManager.getCanvasSize()).thenReturn(expectedMode); pictureManager.getPictureMode(); PowerMockito.verifyStatic(Log.class); Log.i("PictureManager", "getPictureMode: result = " + expectedMode); } @Test public void testNullContextHandling() { resetSingleton(); // 现在安全了 PictureManager uninitialized = PictureManager.getInstance(); uninitialized.setPictureMode(1); verify(mockOptixDisplayManager, never()).setCanvasSize(anyInt()); } @Test public void testMultipleInitializations() { Context secondContext = Mockito.mock(Context.class); pictureManager.init(secondContext); // 应该成功执行,不会抛出异常 pictureManager.setPictureMode(8); verify(mockOptixDisplayManager).setCanvasSize(8); } @Test public void testListenerRemoval() { pictureManager.setPictureModeChangedListener(null); pictureManager.setPictureMode(9); verify(mockListener, never()).onPictureModeChanged(anyInt()); } } 上面是我的测试代码,下面是出现的报错,请告诉我怎么解决 Failed to transform class with name com.st.systemsettings.manager.OptixDisplayManager. Reason: [source error] cannot find constructor android.os.UserHandle(int) java.lang.IllegalStateException: Failed to transform class with name com.st.systemsettings.manager.OptixDisplayManager. Reason: [source error] cannot find constructor android.os.UserHandle(int)
最新发布
07-23
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不识君的荒漠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值