UT和PowerMock

PowerMock 简介

要测试的方法会引用很多外部依赖的对象(获得连接getConnection,getAdmin),外部对象不可控,模拟(mock)外部对象使其可控。

核心思想

你要mock的方法必须是你mock的对象调的。原有的对象只会走原有的逻辑。

什么情况需要加注解:

@RunWith(PowerMockRunner.class)
@PrepareForTest ( { YourClassWithEgStaticMethod.class })
  1. PowerMockito.whenNew方法时,注解@PrepareForTest里写的类是需要mock的new对象代码所在的类
  2. 普通对象的finil方法,注解里写filal方法所在的类
  3. 普通对象的static方法,注解里写static方法所在的类
PowerMockito.mockStatic(ClassDependency.class);
PowerMockito.when(ClassDependency.isExist()).thenReturn(true);
  1. private方法,注解里private方法所在类
PowerMockito.when(other.pub(Mockito.anyString())).thenCallRealMethod();
PowerMockito.when(other, "pri", Mockito.anyString()).thenReturn(" $$ I am handsome %% private.");
  1. 系统类的静态和final方法,注解里写的类是需要调用系统方法所在的类

其他

  1. Void方法 不用加注解,but:
PowerMockito.doNothing().when(mockUnder.dovoid(Mockito.anyString()));   //WRONG
PowerMockito.doNothing().when(mockUnder).dovoid(Mockito.anyString());   //RIGHT
PowerMockito.doNothing().when(mockUnder,"dovoid","aa","bb");   //RIGHT
PowerMockito.when(mockUnder,"dovoid","aa","bb").thenAnswer(answer);   //RIGHT

推荐以下的写法,因为使用范围比较广

PowerMockito.doNothing().when(mockUnder,"dovoid","aa","bb");
PowerMockito.doNothing().when(UnderTest.class,"dovoid","aa","bb");
PowerMockito.when(mockUnder,"dovoid","aa","bb").thenAnswer(answer);
PowerMockito.when(under1, "isDpa", Mockito.anyString()).thenReturn(true);
  1. Spy
    类C的m1方法掉了m2,想覆盖类C的m1,模拟打桩m2
    可以考虑用spy
  2. Answer
    Object[] args = invocation.getArguments();
    注意传入的参数,不要越界
  3. 希望多次返回结果不同,比如第一次返回true,第二次false
    PowerMockito.when(under1.isDpa(Mockito.anyString())).thenReturn(true).thenReturn(false);
  4. Mock 抛异常
    PowerMockito.doThrow(new NullPointerException()).when(other).doExcep(Mockito.anyString());
    抛的异常必须是mock的方法可能抛的,否则mock会抛异常
    所以不要在测试用例的大catch里写Assert.assertTrue(true);来判断程序抛异常,因为这个异常很可能是mock的时候就抛了。
    @Test
    public void test() 
    {
        try
        {
            // do some test
        }
        catch (Exception e)
        {
            e.printStackTrace();
            Assert.assertTrue(false);
        }
    }
  1. 反射
UnderTest under = new UnderTest();
StudentMgr stuMgr = PowerMockito.mock(StudentMgr.class);
Class<AbstractClass> clazz = AbstractClass.class;
Field field = clazz.getDeclaredField("studentMgr");
field.setAccessible(true);
field.set(under, stuMgr);

常见问题

  1. InitializationError
    @Test 注解没加
    缺jar包
    Junit 版本不对(junit不能用4.12)
  2. spy() vs mock()

spy() is used when you want the real code of the class you are spying on to do its job, but be able to intercept method calls and return values. mock() is used to make a new class that has the same interface as the class you are mocking, but with NO code inside...

注意事项

  1. UT结束清理环境
    @BeforeClass        //测试class前
    public static void setUpBeforeClass() throws Exception
    {
    }
    @AfterClass     //测试class前
    public static void tearDownAfterClass() throws Exception
    {
    }
    @Before     //每个Test前
    public void setUp() throws Exception
    {
    }
    @After      //每个Test后
    public void tearDown() throws Exception
    {
    }
  1. setUp()中mock的东西会影响到每个Test
    注意:

mock singleton static final : mock before other code new it.
mock单例要在其他代码new它前

  1. 测试的目的
    发现代码的缺陷,发现问题,及时与开发确认,不要只为了覆盖率去写测试。
    能全流程尽量全流程

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 138,267评论 20 591
  • 本文介绍了Android单元测试入门所需了解的内容,包括JUnit、Mockito和PowerMock的使用,怎样...
    于卫国阅读 2,250评论 0 4
  • Instrumentation介绍 Instrumentation是个什么东西? Instrumentation测...
    打不死的小强qz阅读 4,624评论 2 39
  • 背景 在写单元测试的过程中,一个很普遍的问题是,要测试的目标类会有很多依赖,这些依赖的类/对象/资源又会有别的依赖...
    johnnycmj阅读 385评论 0 1
  • 跋山涉水做了四个半小时的车程来到了美丽的山城,心情确并不美丽,开会加班,晚上只睡了一个半小时,点了杯美美的冰饮,不...
    Universe_Eva阅读 33评论 0 0