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它前
- 測試的目的
發現代碼的缺陷,發現問題,及時與開發確認,不要只為了覆蓋率去寫測試。
能全流程盡量全流程