Java_UT_Mock系列之-04Powermock与单例模式

测试场景

单例模式是常见的一种创建型设计模式,保证了采用该模式的类的实例的全局唯一性。但对于UT来说,由于其屏蔽了类的创建过程,其testability是有待商榷的。
如以下案例,

public class ClassToUseSingleton {
    public String invokeSingleton()
    {
        return Singleton.getInstance().printHelloWorld( "Hi!!!" );
    }
}

上述被测应用中的invokeSingleton方法调用了一个Singleton单例类的方法来完成某项特定工作。该单例类的源码如下:

public class Singleton
{
    public String printHelloWorld( String value )
    {
        StringBuilder stringBuilder
            = new StringBuilder( "The string value is: " );
        return stringBuilder.append( value ).toString();
    }

    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

Mock实现

通过观察上述代码,可以发现mock的难点在于

  1. 私有内部类
    该单例模式采取了内部类的方式SingletonInstance来持有一个私有且final的Singleton 对象实例,这样就保证了Singleton实例的全局唯一性,并且是线程安全的。
    private static final Singleton INSTANCE
  2. 静态方法/变量
    getInstance()是一个静态方法,常用的通过new的方式来注入一个mock对象的方法不能使用。
    而通过Powermock,则可以解决上述问题。主要思路是,当调用getInstance()方法时,返回一个被mock过的Singleton 实例来替换对SingletonInstance.INSTANCE的调用。
    示例代码如下
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 org.powermock.reflect.Whitebox;
import static org.junit.Assert.assertEquals;
@RunWith( PowerMockRunner.class )
@PrepareForTest(Singleton.class )
public class ClassToUseSingletonTest
{
    @Test
    public void testSingeton() throws Exception {
    Singleton mockSingleton =  PowerMockito.mock(Singleton.class);
        Class clazz = Whitebox.getInnerClassType(Singleton.class, "SingletonInstance");
        Whitebox.setInternalState(clazz, "INSTANCE", mockSingleton);
        PowerMockito.when( mockSingleton.printHelloWorld( Mockito.anyString() ) )
                    .thenReturn( "Mocked!!" );
        assertEquals( "Mocked!!",
                      new ClassToUseSingleton().invokeSingleton() );
    }
}

案例分析

这里主要使用了Whitebox这个工具,

Class clazz = Whitebox.getInnerClassType (Singleton.class, "SingletonInstance");

通过这行代码,获取到了内部类SingletonInstance。
然后,再将mockSingleton赋给内部私有变量 "INSTANCE",

Whitebox.setInternalState(clazz, "INSTANCE", mockSingleton);

这样,就实现了当调用SingletonInstance.INSTANCE时,将返回被mock过的Singleton对象mockSingleton ,也就是实现了对于单例模式的模拟。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 单例模式(SingletonPattern)一般被认为是最简单、最易理解的设计模式,也因为它的简洁易懂,是项目中最...
    成热了阅读 9,897评论 4 34
  • 前言 本文主要参考 那些年,我们一起写过的“单例模式”。 何为单例模式? 顾名思义,单例模式就是保证一个类仅有一个...
    tandeneck阅读 7,313评论 1 8
  • 单例:意思就是只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单...
    CoderZS阅读 3,728评论 1 13
  • Day52 今天坐了一天的车,听了好多有年代的歌,什么小白杨啊,我家住在黄土高原,什么什么的,车上的电视播了一路*...
    小懒说Yolo阅读 1,364评论 0 1
  • 今天大姐夫的父亲去世了,癌症74岁。记得小时候去姐夫家,这个伯伯很爱笑也很爱逗我玩,我在大姐家生活了5年,非常尊...
    苏君诺阅读 2,738评论 1 0

友情链接更多精彩内容