PowerMock 简介
要测试的方法会引用很多外部依赖的对象(获得连接getConnection,getAdmin),外部对象不可控,模拟(mock)外部对象使其可控。
核心思想
你要mock的方法必须是你mock的对象调的。原有的对象只会走原有的逻辑。
什么情况需要加注解:
@RunWith(PowerMockRunner.class)
@PrepareForTest ( { YourClassWithEgStaticMethod.class })
- PowerMockito.whenNew方法时,注解@PrepareForTest里写的类是需要mock的new对象代码所在的类
- 普通对象的finil方法,注解里写filal方法所在的类
- 普通对象的static方法,注解里写static方法所在的类
PowerMockito.mockStatic(ClassDependency.class);
PowerMockito.when(ClassDependency.isExist()).thenReturn(true);
- private方法,注解里private方法所在类
PowerMockito.when(other.pub(Mockito.anyString())).thenCallRealMethod();
PowerMockito.when(other, "pri", Mockito.anyString()).thenReturn(" $$ I am handsome %% private.");
- 系统类的静态和final方法,注解里写的类是需要调用系统方法所在的类
其他
- 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);
- Spy
类C的m1方法掉了m2,想覆盖类C的m1,模拟打桩m2
可以考虑用spy - Answer
Object[] args = invocation.getArguments();
注意传入的参数,不要越界 - 希望多次返回结果不同,比如第一次返回true,第二次false
PowerMockito.when(under1.isDpa(Mockito.anyString())).thenReturn(true).thenReturn(false);
- 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);
}
}
- 反射
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);
常见问题
- InitializationError
@Test 注解没加
缺jar包
Junit 版本不对(junit不能用4.12) - 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...
注意事项
- 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
{
}
- setUp()中mock的东西会影响到每个Test
注意:
mock singleton static final : mock before other code new it.
mock单例要在其他代码new它前
- 测试的目的
发现代码的缺陷,发现问题,及时与开发确认,不要只为了覆盖率去写测试。
能全流程尽量全流程