本文將簡單介紹如何使用PowerMock和Mockito來mock
1. 構(gòu)造函數(shù)
2. 靜態(tài)函數(shù)
3. 枚舉實(shí)現(xiàn)的單例
4. 選擇參數(shù)值做為函數(shù)的返回值
5. 在調(diào)用mock出來的方法中,改變方法參數(shù)的值
一點(diǎn)簡要說明:Mockito其實(shí)已經(jīng)可以滿足大部分的需求,但是它的實(shí)現(xiàn)機(jī)制是使用cglib來動(dòng)態(tài)創(chuàng)建接口的類的實(shí)例。但是這種實(shí)現(xiàn)方式不能用于構(gòu)造函數(shù)和靜態(tài)函數(shù),因?yàn)槟切枰褂妙惖淖止?jié)碼(比如使用javassist). 所以我們才需要結(jié)合使用PowerMock.
1. mock構(gòu)造函數(shù), 如果有代碼沒有使用DI注入依賴實(shí)例,在單元測試中可以使用PowerMock來模擬創(chuàng)建對象。
注意的開始兩行的2個(gè)注解 @RunWith 和 @PrepareForTest
@RunWith比較簡單,后面始終是PowerMockRunner.class
@PrepareForText后面需要加的是調(diào)用構(gòu)造函數(shù)的類名,而不是有構(gòu)造函數(shù)的類本身。
在下面的例子中,我們要測試的類是:Helper, 在Helper類中調(diào)用了Somthing類的構(gòu)造函數(shù)來創(chuàng)建實(shí)例。
@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);
// 調(diào)用需要測試方法
helper.doSomething(argument);
// 進(jìn)行驗(yàn)證
verify(mockSomething).doIt();
}
}
public class Helper {
public void doSomething(String arg) {
Something something = new Something(arg);
something.doit();
}
}
2,mock 靜態(tài)函數(shù), 單例模式就是一個(gè)典型的會(huì)調(diào)用靜態(tài)函數(shù)的例子。 注意要點(diǎn)與mock構(gòu)造函數(shù)相同。
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枚舉實(shí)現(xiàn)的單例
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。返回參數(shù)值做為函數(shù)返回值。
mockito 1.9.5之后,提供一個(gè)方便的方法來實(shí)現(xiàn)這個(gè)需要,在這之前可以使用一個(gè)匿名函數(shù)來返回一個(gè)answer來實(shí)現(xiàn)。
when(myMock.myFunction(anyString())).then(returnsFirstArg());
其中returnsFirstArg()是org.mockito.AdditionalAnswers中的一個(gè)靜態(tài)方法。
在這個(gè)類中還有其他的一些類似方法
returnsSecondArg()
returnsLastArg()
ReturnsArgumentAt(int position)
5. 在調(diào)用mock出來的方法中,改變方法參數(shù)的值
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) );