Mockito开发指南
Mockito無法模擬final,static,private、hashCode()、equals()方法。
導(dǎo)入Mockito依賴包:
<dependency><groupId>org.mockito</groupId><artifactId>mockito-all</artifactId><version>1.10.19</version> </dependency>驗證行為是否發(fā)生:Verify()
//Let's import Mockito statically so that the code looks clearerimport static org.mockito.Mockito.*;//mock creationList<String> mockedList = mock(List.class);//using mock objectmockedList.add("one");mockedList.clear();//verificationverify(mockedList).add("one");verify(mockedList).clear();一旦mock對象創(chuàng)建,他會記錄所有發(fā)生過的事件,通過verify可以驗證之前發(fā)生的任何你感興趣的事件。
模擬期望的結(jié)果 : when(mockedList.get(0)).thenReturn("first");
//You can mock concrete classes, not just interfacesLinkedList mockedList = mock(LinkedList.class);//stubbingwhen(mockedList.get(0)).thenReturn("first");//1doReturn("first").when(mockedList).get(0)//2 //1和2作用一樣when(mockedList.get(1)).thenThrow(new RuntimeException());//following prints "first"System.out.println(mockedList.get(0));//following throws runtime exceptionSystem.out.println(mockedList.get(1));//following prints "null" because get(999) was not stubbedSystem.out.println(mockedList.get(999));一旦mock之后,每次返回的值都是mock的期望值。
參數(shù)匹配
通常情況下,Mockito匹配方法參數(shù)使用的是對象的equals方法,當(dāng)需要更靈活的匹配方式則就需要使用參數(shù)匹配器。
//stubbing using built-in anyInt() argument matcherwhen(mockedList.get(anyInt())).thenReturn("element");//following prints "element"System.out.println(mockedList.get(999));//you can also verify using an argument matcherverify(mockedList).get(anyInt());我們也可以自定義參數(shù)匹配器。只要實現(xiàn)ArgumentMatcher<T>接口即可,【版本2.1.0才加入】
class ListOfTwoElements implements ArgumentMatcher<List> {public boolean matches(List list) {return list.size() == 2;}public String toString() {//printed in verification errorsreturn "[list of 2 elements]";}}List mock = mock(List.class);when(mock.addAll(argThat(new ListOfTwoElements()))).thenReturn(true);mock.addAll(Arrays.asList("one", "two"));verify(mock).addAll(argThat(new ListOfTwoElements()));關(guān)于參數(shù)匹配器的注意點,如果方法參數(shù)有一個使用了參數(shù)匹配器,則所有的參數(shù)都要使用參數(shù)匹配器。
verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));//above is correct - eq() is also an argument matcher//不正確的使用verify(mock).someMethod(anyInt(), anyString(), "third argument");//above is incorrect - exception will be thrown because third argument is given without an argument matcher.驗證實際調(diào)用次數(shù)、至少次數(shù)、從沒調(diào)用
//using mockmockedList.add("once");mockedList.add("twice");mockedList.add("twice");mockedList.add("three times");mockedList.add("three times");mockedList.add("three times");//following two verifications work exactly the same - times(1) is used by defaultverify(mockedList).add("once");verify(mockedList, times(1)).add("once");//exact number of invocations verificationverify(mockedList, times(2)).add("twice");verify(mockedList, times(3)).add("three times");//verification using never(). never() is an alias to times(0)verify(mockedList, never()).add("never happened");//verification using atLeast()/atMost()verify(mockedList, atLeastOnce()).add("three times");verify(mockedList, atLeast(2)).add("five times");verify(mockedList, atMost(5)).add("three times");模擬void方法拋出異常
doThrow(new RuntimeException()).when(mockedList).clear();//following throws RuntimeException:mockedList.clear();驗證調(diào)用順序
// A. Single mock whose methods must be invoked in a particular orderList singleMock = mock(List.class);//using a single mocksingleMock.add("was added first");singleMock.add("was added second");//create an inOrder verifier for a single mockInOrder 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 orderList firstMock = mock(List.class);List secondMock = mock(List.class);//using mocksfirstMock.add("was called first");secondMock.add("was called second");//create inOrder object passing any mocks that need to be verified in orderInOrder inOrder = inOrder(firstMock, secondMock);//following will make sure that firstMock was called before secondMockinOrder.verify(firstMock).add("was called first");inOrder.verify(secondMock).add("was called second");// Oh, and A + B can be mixed together at will驗證mock對象沒有進(jìn)行交互
//using mocks - only mockOne is interactedmockOne.add("one");//ordinary verificationverify(mockOne).add("one");//verify that method was never called on a mockverify(mockOne, never()).add("two");//verify that other mocks were not interactedverifyZeroInteractions(mockTwo, mockThree);//verifyNoMoreInteractions(mockTwo, mockThree);//功能以verifyZeroInteractions()一樣 //用于校驗是否所有的交互已經(jīng)verify了,如果沒有則報錯通過注解@Mock簡化Mock對象的創(chuàng)建,提供了三種方法初始化注解
//1 public class ArticleManagerTest {@Mock private ArticleCalculator calculator;@Mock private ArticleDatabase database;@Mock private UserProvider userProvider;private ArticleManager manager;@Beforepublic void setUp(){MockitoAnnotations.initMocks(this);}}//2 @RunWith(MockitoJUnitRunner.class)public class ExampleTest {@Mockprivate List list;@Testpublic void shouldDoSomething() {list.add(100);}}//3 public class ExampleTest {@Rule public MockitoRule rule = MockitoJUnit.rule();@Mockprivate List list;@Testpublic void shouldDoSomething() {list.add(100);}}針對同一個方法調(diào)用多次返回不同值的作法
//1when(mock.someMethod("some arg")).thenReturn("foo1").thenReturn("foo");//First call: prints "foo1" System.out.println(mock.someMethod("some arg"));//Second call: prints "foo"System.out.println(mock.someMethod("some arg"));//Any consecutive call: prints "foo" as well (last stubbing wins).System.out.println(mock.someMethod("some arg"));//2 也可以簡寫when(mock.someMethod("some arg")).thenReturn("one", "two", "three");//3但如果寫成這樣,后面的就會覆蓋簽名的mock,下面每次調(diào)用mock.someMethod("some arg")只會返回"two" //All mock.someMethod("some arg") calls will return "two"when(mock.someMethod("some arg")).thenReturn("one")when(mock.someMethod("some arg")).thenReturn("two")使用Answer接口模擬返回的期望值
when(mock.someMethod(anyString())).thenAnswer(new Answer() {Object answer(InvocationOnMock invocation) {Object[] args = invocation.getArguments();Object mock = invocation.getMock();return "called with arguments: " + args;}});//the following prints "called with arguments: foo"System.out.println(mock.someMethod("foo"));doReturn、 doThrow、 doAnswer、doNothing、doCallRealMethod的使用
1.可以用來模擬void方法
2.可以模擬spy方法創(chuàng)建的對象(尤其在when().thenXXX()拋異常時)
3.替換when().thenXxx()
doThrow(new RuntimeException()).when(mockedList).clear();//following throws RuntimeException:mockedList.clear();通過Spy創(chuàng)建真實對象的原型
除非模擬期望結(jié)果,否則將調(diào)用真實的方法,與mock最大的不同就是mock出來的對象所有的方法都是調(diào)用模擬的,除非使用doCallRealMethod()才調(diào)用真實方法
List list = new LinkedList();List spy = spy(list);//optionally, you can stub out some methods:when(spy.size()).thenReturn(100);//using the spy calls *real* methodsspy.add("one");spy.add("two");//prints "one" - the first element of a listSystem.out.println(spy.get(0));//size() method was stubbed - 100 is printedSystem.out.println(spy.size());//optionally, you can verifyverify(spy).add("one");verify(spy).add("two");//當(dāng)when().thenXXX()報錯時,則使用doXXX().when().methodCall();List list = new LinkedList();List spy = spy(list);//Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)when(spy.get(0)).thenReturn("foo");//You have to use doReturn() for stubbingdoReturn("foo").when(spy).get(0);當(dāng)使用mock()時,針對沒有模擬的方法,如何改變其返回值呢
(目前返回null)
Foo mock = mock(Foo.class, Mockito.RETURNS_SMART_NULLS);Foo mockTwo = mock(Foo.class, new YourOwnAnswer());可以指定調(diào)用實際方法,也可以自定義answer實例....
捕獲參數(shù)來進(jìn)一步斷言(ArgumentCaptor)
@Testpublic void capturing_args(){PersonDao personDao = mock(PersonDao.class);PersonService personService = new PersonService(personDao);ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);personService.update(1,"jack");verify(personDao).update(argument.capture());assertEquals(1,argument.getValue().getId());assertEquals("jack",argument.getValue().getName());}class Person{private int id;private String name;Person(int id, String name) {this.id = id;this.name = name;}public int getId() {return id;}public String getName() {return name;}}interface PersonDao{public void update(Person person);}class PersonService{private PersonDao personDao;PersonService(PersonDao personDao) {this.personDao = personDao;}public void update(int id,String name){personDao.update(new Person(id,name));}}調(diào)用真實方法的mock
//方法1 //you can create partial mock with spy() method:List list = spy(new LinkedList());//方法2//you can enable partial mock capabilities selectively on mocks:Foo mock = mock(Foo.class);//Be sure the real implementation is 'safe'.//If real implementation throws exceptions or depends on specific state of the object then you're in trouble.when(mock.someMethod()).thenCallRealMethod();重置mock對象
List mock = mock(List.class);when(mock.size()).thenReturn(10);mock.add(1);System.out.println(mock.size());//return 10reset(mock);//at this point the mock forgot any interactions & stubbingSystem.out.println(mock.size());//return 0注解@Captor【對應(yīng)ArgumentCaptor】,@Spy【spy()】, @InjectMocks【將mock和spy對象注入到當(dāng)前對象中】
public class Test{@Captor ArgumentCaptor<AsyncCallback<Foo>> captor;@Beforepublic void init(){MockitoAnnotations.initMocks(this);}@Test public void shouldDoSomethingUseful() {//...verify(mock).doStuff(captor.capture());assertEquals("foo", captor.getValue());}} public class Test{//Instance for spying is created by calling constructor explicitly:@Spy Foo spyOnFoo = new Foo("argument");//Instance for spying is created by mockito via reflection (only default constructors supported):@Spy Bar spyOnBar;@Beforepublic void init(){MockitoAnnotations.initMocks(this);}...} //@RunWith(MockitoJUnitRunner.class) public class ArticleManagerTest extends SampleBaseTestCase {@Mock private ArticleCalculator calculator;@Mock(name = "database") private ArticleDatabase dbMock; // note the mock name attribute@Spy private UserProvider userProvider = new ConsumerUserProvider();@InjectMocks private ArticleManager manager;@Test public void shouldDoSomething() {manager.initiateArticle();verify(database).addListener(any(ArticleListener.class));}}public class SampleBaseTestCase {@Before public void initMocks() {MockitoAnnotations.initMocks(this);}}驗證在指定是時間內(nèi)執(zhí)行完方法
verify(mock, timeout(100)).someMethod();//above is an alias to:verify(mock, timeout(100).times(1)).someMethod();//passes when someMethod() is called *exactly* 2 times within given time spanverify(mock, timeout(100).times(2)).someMethod();//passes when someMethod() is called *at least* 2 times within given time spanverify(mock, timeout(100).atLeast(2)).someMethod();//verifies someMethod() within given time span using given verification mode//useful only if you have your own custom verification modes.verify(mock, new Timeout(100, yourOwnVerificationMode)).someMethod();大部分功能介紹完了,如果需要更深入的使用Mockito,請參考官方文檔,地址如下:
http://static.javadoc.io/org.mockito/mockito-core/2.7.22/org/mockito/Mockito.html
?
轉(zhuǎn)載于:https://my.oschina.net/javastorm/blog/881049
總結(jié)
以上是生活随笔為你收集整理的Mockito开发指南的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 发烧级蓝牙耳机哪款音质最好?200元内性
- 下一篇: iPhone的备忘录如何进行撤销?