本文將簡單介紹如何使用PowerMock和Mockito來mock
1. 構造函數
2. 靜態函數
3. 枚舉實現的單例
4. 選擇參數值做為函數的返回值
5. 在調用mock出來的方法中,改變方法參數的值
一點簡要說明:Mockito其實已經可以滿足大部分的需求,但是它的實現機制是使用cglib來動態創建接口的類的實例。但是這種實現方式不能用于構造函數和靜態函數,因為那需要使用類的字節碼(比如使用javassist). 所以我們才需要結合使用PowerMock.
1. mock構造函數, 如果有代碼沒有使用DI注入依賴實例,在單元測試中可以使用PowerMock來模擬創建對象。
注意的開始兩行的2個注解 @RunWith 和 @PrepareForTest
@RunWith比較簡單,后面始終是PowerMockRunner.class
@PrepareForText后面需要加的是調用構造函數的類名,而不是有構造函數的類本身。
在下面的例子中,我們要測試的類是:Helper, 在Helper類中調用了Somthing類的構造函數來創建實例。
@RunWith(PowerMockRunner.class)
@PrepareForTest(Helper.class)
public class HelperTest {
@Mock
private Something mockSomething;
@InjectMocks
private Helper helper;
@Test
public void doSomething() throws Exception {
String argument = "arg";
PowerMockito.whenNew(Something.class).withArguments(argument).thenReturn(mockSomething);
// 調用需要測試方法
helper.doSomething(argument);
// 進行驗證
verify(mockSomething).doIt();
}
}
public class Helper {
public void doSomething(String arg) {
Something something = new Something(arg);
something.doit();
}
}
2,mock 靜態函數, 單例模式就是一個典型的會調用靜態函數的例子。 注意要點與mock構造函數相同。
class ClassWithStatics {
public static String getString() {
return "String";
}
public static int getInt() {
return 1;
}
}
@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassWithStatics.class)
public class StubJustOneStatic {
@Test
public void test() {
PowerMockito.mockStatic(ClassWithStatics.class);
when(ClassWithStatics.getString()).thenReturn("Hello!");
System.out.println("String: " + ClassWithStatics.getString());
System.out.println("Int: " + ClassWithStatics.getInt());
}
}
3。mock枚舉實現的單例
SingletonObject.java
public enum SingletonObject {
INSTANCE;
private int num;
protected void setNum(int num) {
this.num = num;
}
public int getNum() {
return num;
}
}
SingletonConsumer.java
public class SingletonConsumer {
public String consumeSingletonObject() {
return String.valueOf(SingletonObject.INSTANCE.getNum());
}
}
SingletonConsumerTest.java
@RunWith(PowerMockRunner.class)
@PrepareForTest({SingletonObject.class})
public class SingletonConsumerTest {
@Test public void testConsumeSingletonObject() throws Exception {
SingletonObject mockInstance = mock(SingletonObject.class);
Whitebox.setInternalState(SingletonObject.class, "INSTANCE", mockInstance);
when(mockInstance.getNum()).thenReturn(42);
assertEquals("42", new SingletonConsumer().consumeSingletonObject());
}
}
4。返回參數值做為函數返回值。
mockito 1.9.5之后,提供一個方便的方法來實現這個需要,在這之前可以使用一個匿名函數來返回一個answer來實現。
when(myMock.myFunction(anyString())).then(returnsFirstArg());
其中returnsFirstArg()是org.mockito.AdditionalAnswers中的一個靜態方法。
在這個類中還有其他的一些類似方法
returnsSecondArg()
returnsLastArg()
ReturnsArgumentAt(int position)
5. 在調用mock出來的方法中,改變方法參數的值
when( myMock.someMethod( any( List.class ) ) ).thenAnswer( ( new Answer<Void>() {
@Override
public Void answer( InvocationOnMock invocation )
throws Throwable {
Object[] args = invocation.getArguments();
List arg1 = (List)args[0];
arg1.add("12345");
return null;
}
} ) );
Verifying with generic parameters
verify(someService).process(Matchers.<Collection<Person>>any());
verify(adunoMasterBaseProcessor).processBinFiles( anyListOf(File.class) );