關(guān)鍵詞:Mockito
以下內(nèi)容翻譯整理自:
Mockito latest documentation
[譯] 使用強(qiáng)大的 Mockito 測試框架來測試你的代碼
Unit tests with Mockito - Tutorial
When/how to use Mockito Answer(需要翻墻)
使用Mockito對(duì)異步方法進(jìn)行單元測試
2. 使用mock對(duì)象進(jìn)行測試
單元測試應(yīng)該盡可能隔離其他類或系統(tǒng)的影響占贫。
- dummy object
- Fake objects
- stub class
- mock object
可以使用mock框架創(chuàng)建mock對(duì)象來模擬類巴刻,mock框架允許在運(yùn)行時(shí)創(chuàng)建mock對(duì)象,并定義它們的行為畴栖。
Mockito是目前流行的mock框架投队,可以配合JUnit使用寝志。Mockito支持創(chuàng)建和設(shè)置mock對(duì)象。使用Mockito可以顯著的簡化對(duì)那些有外部依賴的類的測試缸剪。
- mock測試代碼中的外部依賴
- 執(zhí)行測試
- 驗(yàn)證代碼是否執(zhí)行正確
4. 使用Mockito API
Static imports
添加static importorg.mockito.Mockito.*;
Creating and configuring mock objects with Mockito
Mockito支持通過靜態(tài)方法mock()
創(chuàng)建mock對(duì)象吗铐,也可以使用@Mock
注解。如果使用注解的方式杏节,必須初始化mock對(duì)象唬渗。使用MockitoRule
典阵,調(diào)用靜態(tài)方法MockitoAnnotations.initMocks(this)
初始化標(biāo)示的屬性字段。
import static org.mockito.Mockito.*;
public class MockitoTest {
@Mock
MyDatabase databaseMock;
@Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
@Test
public void testQuery() {
ClassToTest t = new ClassToTest(databaseMock);
boolean check = t.query("* from t");
assertTrue(check);
verify(databaseMock).query("* from t");
}
}
-
Configuring mocks
-
when(…?.).thenReturn(…?.)
用于指定條件滿足時(shí)的返回值镊逝,也可以根據(jù)不同的傳入?yún)?shù)返回不同的值壮啊。 -
doReturn(…?).when(…?).methodCall
作用類似,但是用于返回值為void的函數(shù)撑蒜。
-
Verify the calls on the mock objects
Mockito會(huì)跟蹤mock對(duì)象所有的函數(shù)調(diào)用以及它們的參數(shù)歹啼,可以用verify()
驗(yàn)證
一個(gè)函數(shù)有沒有被調(diào)用with指定的參數(shù)。這個(gè)被稱為"behavior testing"Wrapping Java objects with Spy
@Spy
或spy()
方法用于封裝實(shí)際的對(duì)象座菠。除非有特殊聲明(stub)狸眼,都會(huì)真正的調(diào)用對(duì)象的方法。-
Using @InjectMocks for dependency injection via Mockito
- You also have the
@InjectMocks
annotation which tries to do constructor, method or field dependency injection based on the type.
- You also have the
Capturing the arguments
ArgumentCaptor
允許我們在verification期間訪問函數(shù)的參數(shù)辈灼。在捕獲這些函數(shù)參數(shù)后份企,可以用于測試。
- Limitations
以下不能使用Mockito測試- final classes
- anonymous classes
- primitive types
1. Mockito Answer的使用
A common usage of Answer is to stub asynchronous methods that have callbacks.
doAnswer(new Answer<Void>() {
public Void answer(InvocationOnMock invocation) {
Callback callback = (Callback) invocation.getArguments()[0];
callback.onSuccess(cannedData);
return null;
}
}).when(service).get(any(Callback.class));
Answer can also be used to make smarter stubs for synchronous methods.
when(translator.translate(any(String.class))).thenAnswer(reverseMsg())
...
// extracted a method to put a descriptive name
private static Answer<String> reverseMsg() {
return new Answer<String>() {
public String answer(InvocationOnMock invocation) {
return reverseString((String) invocation.getArguments()[0]));
}
}
}
Mockito限制
- final classes
- anonymous classes
- primitive types
Mockito示例
1. Let's verify some behaviour!
//Let's import Mockito statically so that the code looks clearer
import static org.mockito.Mockito.*;
//mock creation
List mockedList = mock(List.class);
//using mock object
mockedList.add("one");
mockedList.clear();
//verification
verify(mockedList).add("one");
verify(mockedList).clear();
驗(yàn)證某些操作是否執(zhí)行
Once created, a mock will remember all interactions. Then you can selectively verify whatever interactions you are interested in.
2. How about some stubbing?
//You can mock concrete classes, not just interfaces
LinkedList mockedList = mock(LinkedList.class);
//stubbing
when(mockedList.get(0)).thenReturn("first");
when(mockedList.get(1)).thenThrow(new RuntimeException());
//following prints "first"
System.out.println(mockedList.get(0));
//following throws runtime exception
System.out.println(mockedList.get(1));
//following prints "null" because get(999) was not stubbed
System.out.println(mockedList.get(999));
//Although it is possible to verify a stubbed invocation, usually **it's just redundant**
//If your code cares what get(0) returns, then something else breaks (often even before verify() gets executed).
//If your code doesn't care what get(0) returns, then it should not be stubbed. Not convinced? See [here](http://monkeyisland.pl/2008/04/26/asking-and-telling).
verify(mockedList).get(0);
By default, for all methods that return a value, a mock will return either null, a a primitive/primitive wrapper value, or an empty collection, as appropriate. For example 0 for an int/Integer and false for a boolean/Boolean.
3. Argument matchers
//stubbing using built-in anyInt() argument matcher
when(mockedList.get(anyInt())).thenReturn("element");
//stubbing using custom matcher (let's say isValid() returns your own matcher implementation):
when(mockedList.contains(argThat(isValid()))).thenReturn("element");
//following prints "element"
System.out.println(mockedList.get(999));
//**you can also verify using an argument matcher**
verify(mockedList).get(anyInt());
//**argument matchers can also be written as Java 8 Lambdas**
verify(mockedList).add(someString -> someString.length() > 5);
If you are using argument matchers, all arguments have to be provided by matchers.
5. Stubbing void methods with exceptions
doThrow(new RuntimeException()).when(mockedList).clear();
//following throws RuntimeException:
mockedList.clear();
6. Verification in order
// A. Single mock whose methods must be invoked in a particular order
List singleMock = mock(List.class);
//using a single mock
singleMock.add("was added first");
singleMock.add("was added second");
//create an inOrder verifier for a single mock
InOrder inOrder = inOrder(singleMock);
//following will make sure that add is first called with "was added first, then with "was added second"
inOrder.verify(singleMock).add("was added first");
inOrder.verify(singleMock).add("was added second");
// B. Multiple mocks that must be used in a particular order
List firstMock = mock(List.class);
List secondMock = mock(List.class);
//using mocks
firstMock.add("was called first");
secondMock.add("was called second");
//create inOrder object passing any mocks that need to be verified in order
InOrder inOrder = inOrder(firstMock, secondMock);
//following will make sure that firstMock was called before secondMock
inOrder.verify(firstMock).add("was called first");
inOrder.verify(secondMock).add("was called second");
// Oh, and A + B can be mixed together at will
7. Making sure interaction(s) never happened on mock
//using mocks - only mockOne is interacted
mockOne.add("one");
//ordinary verification
verify(mockOne).add("one");
//verify that method was never called on a mock
verify(mockOne, never()).add("two");
//verify that other mocks were not interacted
verifyZeroInteractions(mockTwo, mockThree);
8. Finding redundant invocations
//using mocks
mockedList.add("one");
mockedList.add("two");
verify(mockedList).add("one");
//following verification will fail
verifyNoMoreInteractions(mockedList);
verifyNoMoreInteractions()
is a handy assertion from the interaction testing toolkit. Use it only when it's relevant. Abusing it leads to overspecified, less maintainable tests.