美文网首页软件自动化测试
Java_UT_Mock系列之-04Powermock与单例模式

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

作者: antony已经被占用 | 来源:发表于2018-06-25 21:31 被阅读33次

    测试场景

    单例模式是常见的一种创建型设计模式,保证了采用该模式的类的实例的全局唯一性。但对于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 ,也就是实现了对于单例模式的模拟。

    相关文章

      网友评论

      本文标题:Java_UT_Mock系列之-04Powermock与单例模式

      本文链接:https://www.haomeiwen.com/subject/mqsuyftx.html