Java_UT_Mock系列之-04Powermock與單例模式

測試場景

單例模式是常見的一種創(chuàng)建型設(shè)計模式,保證了采用該模式的類的實例的全局唯一性。但對于UT來說,由于其屏蔽了類的創(chuàng)建過程,其testability是有待商榷的。
如以下案例,

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

上述被測應(yīng)用中的invokeSingleton方法調(diào)用了一個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實現(xiàn)

通過觀察上述代碼,可以發(fā)現(xiàn)mock的難點在于

  1. 私有內(nèi)部類
    該單例模式采取了內(nèi)部類的方式SingletonInstance來持有一個私有且final的Singleton 對象實例,這樣就保證了Singleton實例的全局唯一性,并且是線程安全的。
    private static final Singleton INSTANCE
  2. 靜態(tài)方法/變量
    getInstance()是一個靜態(tài)方法,常用的通過new的方式來注入一個mock對象的方法不能使用。
    而通過Powermock,則可以解決上述問題。主要思路是,當(dāng)調(diào)用getInstance()方法時,返回一個被mock過的Singleton 實例來替換對SingletonInstance.INSTANCE的調(diào)用。
    示例代碼如下
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");

通過這行代碼,獲取到了內(nèi)部類SingletonInstance。
然后,再將mockSingleton賦給內(nèi)部私有變量 "INSTANCE",

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

這樣,就實現(xiàn)了當(dāng)調(diào)用SingletonInstance.INSTANCE時,將返回被mock過的Singleton對象mockSingleton ,也就是實現(xiàn)了對于單例模式的模擬。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 單例模式(SingletonPattern)一般被認為是最簡單、最易理解的設(shè)計模式,也因為它的簡潔易懂,是項目中最...
    成熱了閱讀 4,532評論 4 34
  • 前言 本文主要參考 那些年,我們一起寫過的“單例模式”。 何為單例模式? 顧名思義,單例模式就是保證一個類僅有一個...
    tandeneck閱讀 2,623評論 1 8
  • 單例:意思就是只有一個實例。單例模式確保某一個類只有一個實例,而且自行實例化并向整個系統(tǒng)提供這個實例。這個類稱為單...
    CoderZS閱讀 639評論 1 13
  • Day52 今天坐了一天的車,聽了好多有年代的歌,什么小白楊啊,我家住在黃土高原,什么什么的,車上的電視播了一路*...
    小懶說Yolo閱讀 188評論 0 1
  • 今天大姐夫的父親去世了,癌癥74歲。記得小時候去姐夫家,這個伯伯很愛笑也很愛逗我玩,我在大姐家生活了5年,非常尊...
    蘇君諾閱讀 368評論 1 0

友情鏈接更多精彩內(nèi)容