Open diguage opened 5 years ago
//mock creation
List mockedList = mock(List.class);
//using mock object
mockedList.add("one");
mockedList.clear();
//verification
verify(mockedList).add("one");
verify(mockedList).clear();
Once created, a mock will remember all interactions. Then you can selectively verify whatever interactions you are interested in.
D瓜哥注:这里可以校验被调用的次数,已经方法传入的参数。
ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
verify(mockedList).add(argumentCaptor.capture());
String one = argumentCaptor.getValue();
//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.
verify(mockedList).get(0); // 不明白这是啥意思。
D瓜哥注:
mock
接口: mock(List.class)
;List mockedList = mock(List.class);
when(mockedList.get(anyInt())).thenReturn("element");
// when(mockedList.contains(argThat(any()))).thenReturn("element");
System.out.println(mockedList.get(999));
verify(mockedList).get(anyInt());
verify(mockedList).add(argThat((ArgumentMatcher<String>) argument -> argument.length() > 5));
D瓜哥注:
ArgumentMatcher
来自定义参数匹配器anyObject()
, eq()
do not return matchers.List mockedList = mock(List.class);
//using mock
mockedList.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 default
verify(mockedList).add("once");
verify(mockedList, times(1)).add("once");
//exact number of invocations verification
verify(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, atMost(1)).add("once");
verify(mockedList, atLeastOnce()).add("three times");
verify(mockedList, atLeast(2)).add("three times");
verify(mockedList, atMost(5)).add("three times");
times(1) is the default.
可以精确统计每个参数的调用次数。这个厉害了!
List mockedList = mock(List.class);
doThrow(new RuntimeException()).when(mockedList).clear();
//following throws RuntimeException:
mockedList.clear();
// 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");
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 multiInOrder = inOrder(firstMock, secondMock);
//following will make sure that firstMock was called before secondMock
multiInOrder.verify(firstMock).add("was called first");
multiInOrder.verify(secondMock).add("was called second");
// Oh, and A + B can be mixed together at will
D瓜哥注:
List mockOne = mock(List.class);
List mockTwo = mock(List.class);
List mockThree = mock(List.class);
//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");
verifyZeroInteractions(mockTwo, mockThree);
List mockedList = mock(List.class);
//using mocks
mockedList.add("one");
// mockedList.add("two");
verify(mockedList).add("one");
//following verification will fail
verifyNoMoreInteractions(mockedList);
verify()
,则不算多余verifyNoMoreInteractions()
public class ArticleManagerTest {
@Mock private ArticleCalculator calculator;
@Mock private ArticleDatabase database;
@Mock private UserProvider userProvider;
private ArticleManager manager;
// Important! This needs to be somewhere in the base class or a test runner:
MockitoAnnotations.initMocks(testClass);
MockitoAnnotations.initMocks(this);
来初始化一下。MockitoJUnitRunner
来运行,则不需要 MockitoAnnotations.initMocks(this);
SomeObject mock = mock(SomeObject.class);
when(mock.someMethod("some arg"))
.thenThrow(new RuntimeException())
.thenReturn("foo");
//First call: throws runtime exception:
assertThatThrownBy(() -> mock.someMethod("some arg"))
.isInstanceOf(RuntimeException.class);
//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"));
when(mock.someMethod("some arg"))
.thenReturn("one", "two", "three");
System.out.println(mock.someMethod("some arg"));
System.out.println(mock.someMethod("some arg"));
System.out.println(mock.someMethod("some arg"));
System.out.println(mock.someMethod("some arg"));
//All mock.someMethod("some arg") calls will return "two"
when(mock.someMethod("some arg"))
.thenReturn("one");
when(mock.someMethod("some arg"))
.thenReturn("two");
Allows stubbing with generic Answer interface.
when(mock.someMethod(anyString())).thenAnswer(
new Answer<String>() {
@Override
public String answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
Object mock = invocation.getMock();
return "called with arguments: " + Arrays.toString(args);
}
}
);
//Following prints "called with arguments: [foo]"
System.out.println(mock.someMethod("foo"));
可以根据参数来生成不同的返回值。
对于没有返回值的方法,不要需要 stub,则需要通过不同的方式:
List mockList = mock(List.class);
doThrow(new RuntimeException()).when(mockList).clear();
mockList.clear();
类似的方法还有:
doReturn(Object)
doThrow(Throwable...)
doThrow(Class)
doAnswer(Answer)
doNothing()
doCallRealMethod()
这里需要特别注意一点:如果是 spy() 某个实例,使用 when(spy.get(0)).thenReturn("foo");
则会报错。则就可以使用这种方式来实现根据需求返回不同的结果。例如:
List<String> list = new LinkedList<>();
// list.add("Hello");
List<String> 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 stubbing:
doReturn("foo").when(spy).get(0);
System.out.println(spy.get(0));
Spying should be sporadic and overriding exception-stubbing is very rare. Not to mention that in general overridding stubbing is a potential code smell that points out too much stubbing.
You can create spies of real objects. When you use the spy then the real methods are called (unless a method was stubbed).
Real spies should be used carefully and occasionally.
List<String> list = new LinkedList<>();
List<String> spy = spy(list);
//optionally, you can stub out some methods:
when(spy.size()).thenReturn(100);
//using the spy calls *real* methods
spy.add("one");
spy.add("two");
//prints "one" - the first element of a list
System.out.println(spy.get(0));
//size() method was stubbed - 100 is printed
System.out.println(spy.size());
//optionally, you can verify
verify(spy).add("one");
verify(spy).add("two");
SomeClass mock = mock(SomeClass.class, RETURNS_SMART_NULLS);
System.out.println(mock.someMethod("123"));
SomeClass object = mock.object();
System.out.println(object);
System.out.println(mock.intMethod(119));
SomeClass deepStubMock = mock(SomeClass.class, RETURNS_DEEP_STUBS);
System.out.println(deepStubMock.someMethod("123"));
SomeClass deepObject = deepStubMock.object();
System.out.println(deepObject);
System.out.println(deepStubMock.intMethod(119));
SomeClass mockTwo = mock(SomeClass.class, new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return "default answer";
}
});
System.out.println(mockTwo.someMethod("test14"));
System.out.println(mockTwo.method2("test14"));
System.out.println(mockTwo.intMethod(2));
可以使用这个方式定义类中所有方法的返回值。
这里需要注意:
RETURNS_SMART_NULLS
会自动根据方法返回值类型来返回匹配的类型。值得关注的对象
RETURNS_DEFAULTS
RETURNS_SMART_NULLS
RETURNS_MOCKS
RETURNS_DEEP_STUBS
CALLS_REAL_METHODS
RETURNS_SELF
注意: deep stubs
和 mocks
啥区别?
ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);
SomeClass mock = mock(SomeClass.class);
verify(mock).string(argument.capture());
assertThat("John").isEqualTo(argument.getValue());
可以捕获传入的参数。然后进行校验。
Object oriented programming tackles complexity by dividing the complexity into separate, specific, SRPy objects. How does partial mock fit into this paradigm?
Partial mock usually means that the complexity has been moved to a different method on the same object.
//you can create partial mock with spy() method:
List list = spy(new LinkedList());
//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(); // 竟然可以这样调用真实方法。
Please keep us small & focused on a single behavior.
List mock = mock(List.class);
when(mock.size()).thenReturn(10);
mock.add(1);
reset(mock);
//at this point the mock forgot any interactions & stubbing
The only reason we added reset()
method is to make it possible to work with container-injected mocks.
注意:一般情况下,不要使用 reset()
。使用 reset()
是一个坏味道。
Mockito 不能 mock 静态方法;不能 mock hashCode 和 equals 方法;不能 mock 构造函数;
Behavior Driven Development style of writing tests uses //given //when //then comments as fundamental parts of your test methods.
BDDMockito
class introduces an alias so that you stub method calls with BDDMockito.given(Object)
method.
import static org.mockito.BDDMockito.*;
Seller seller = mock(Seller.class);
Shop shop = new Shop(seller);
public void shouldBuyBread() throws Exception {
//given
given(seller.askForBread()).willReturn(new Bread());
//when
Goods goods = shop.buyBread();
//then
assertThat(goods, containBread());
}
TODO: 这里例子不是很明白,还需要再完善一下。
List serializableMock = mock(List.class, withSettings().serializable());
// 对一个真实对象的Spy进行序列化
List<Object> list = new ArrayList<>();
ArrayList spy = mock(ArrayList.class,
withSettings()
.spiedInstance(list)
.defaultAnswer(CALLS_REAL_METHODS)
.serializable());
@Captor
-- 创建 ArgumentCaptor
。不必理会讨厌的泛型问题。@Spy
-- 可以替代 spy(Object)
来创建 Spy。@InjectMocks
-- 自动注入 Mock 或者 Spy。@InjectMocks
can also be used in combination with the @Spy
annotation。注意:这样会创建一个 partial mock。
所有的注解都要被 MockitoAnnotations.initMocks(Object)
来处理。
SomeObject mock = mock(SomeObject.class);
mock.someMethod();
//passes when someMethod() is called no later than within 100 ms
//exits immediately when verification is satisfied (e.g. may not wait full 100 ms)
verify(mock, timeout(100)).someMethod();
//above is an alias to:
verify(mock, timeout(100).times(1)).someMethod();
//passes as soon as someMethod() has been called 2 times under 100 ms
verify(mock, timeout(100).times(2)).someMethod();
//equivalent: this also passes as soon as someMethod() has been called 2 times under 100 ms
verify(mock, timeout(100).atLeast(2)).someMethod();
Mockito 还可以校验超时。
Mockito 会自动实例化 @Spy
和 @InjectMocks
变量。
Car boringStubbedCar = when(mock(Car.class).shiftGear()).thenThrow(EngineNotStarted.class).getMock();
Mockito 可以在一行代码内即创建 Mock 又 Stub。
verifyNoMoreInteractions()
这是何意?看的不是很明白。
//To identify whether a particular object is a mock or a spy:
Mockito.mockingDetails(someObject).isMock();
Mockito.mockingDetails(someObject).isSpy();
//Getting details like type to mock or default answer:
MockingDetails details = mockingDetails(mock);
details.getMockCreationSettings().getTypeToMock();
details.getMockCreationSettings().getDefaultAnswer();
//Getting invocations and stubbings of the mock:
MockingDetails details = mockingDetails(mock);
details.getInvocations();
details.getStubbings();
//Printing all interactions (including stubbing, unused stubs)
System.out.println(mockingDetails(mock).printInvocations());
Mockito 提供了 Mock 对象的相关信息。
final class DontYouDareToMockMe implements List { ... }
DontYouDareToMockMe awesomeList = new DontYouDareToMockMe();
List mock = mock(List.class, delegatesTo(awesomeList));
可以通过这种方式把调用传递给真是对象的对应方法。
这个方式可以用于 final
类的测试。
By default, Mockito uses Byte Buddy to create dynamic proxies.
Mockito 还可以用于 Android 的测试,请看 linkedin/dexmaker
given(dog.bark()).willReturn(2);
// when
...
then(person).should(times(2)).ride(bike);
Mockito 支持 BDD 风格的校验。请引入 org.mockito.BDDMockito
。
//convenience API, new overloaded spy() method:
SomeAbstract spy = spy(SomeAbstract.class);
//Mocking abstract methods, spying default methods of an interface (only available since 2.7.13)
Function function = spy(Function.class);
//Robust API, via settings builder:
OtherAbstract spy = mock(OtherAbstract.class, withSettings()
.useConstructor().defaultAnswer(CALLS_REAL_METHODS));
//Mocking an abstract class with constructor arguments (only available since 2.7.14)
SomeAbstract spy = mock(SomeAbstract.class, withSettings()
.useConstructor("arg1", 123).defaultAnswer(CALLS_REAL_METHODS));
//Mocking a non-static inner abstract class:
InnerAbstract spy = mock(InnerAbstract.class, withSettings()
.useConstructor().outerInstance(outerInstance).defaultAnswer(CALLS_REAL_METHODS));
Mockito 竟然可以为抽象类上创建 Spy 。
// use regular serialization
mock(Book.class, withSettings().serializable());
// use serialization across classloaders
mock(Book.class, withSettings().serializable(ACROSS_CLASSLOADERS));
不知有何用意?
class Line{}
interface Lines extends List<Line>{}
Lines lines = mock(Lines.class, RETURNS_DEEP_STUBS);
// Now Mockito understand this is not an Object but a Line
Line line = lines.iterator().next();
Mockito 对泛型的支持很好。
没搞清楚 MockitoRule
有什么用?而且在 JUnit 5 中,对 rule 做了非常大的重构。
插件机制正在开发。请看 PluginSwitch (Mockito 3.1.0 API)
// will print a custom message on verification failure
verify(mock, description("This will print on failure")).someMethod();
// will work with any verification mode
verify(mock, times(2).description("someMethod should be called twice")).someMethod();
可以自定义提示信息。
// verify a list only had strings of a certain length added to it
// note - this will only compile under Java 8
verify(list, times(2)).add(argThat(string -> string.length() < 5));
// Java 7 equivalent - not as neat
verify(list, times(2)).add(argThat(new ArgumentMatcher(){
public boolean matches(String arg) {
return arg.length() < 5;
}
}));
// more complex Java 8 example - where you can specify complex verification behaviour functionally
verify(target, times(1)).receiveComplexObject(argThat(obj -> obj.getSubObject().get(0).equals("expected")));
// this can also be used when defining the behaviour of a mock under different inputs
// in this case if the input list was fewer than 3 items the mock returns null
when(mock.someMethod(argThat(list -> list.size()<3))).thenReturn(null);
Mockito 中可以使用 Java 8 Lambda 表达式来简化代码。
org.mockito.stubbing.Answer
只有一个方法,可以非常方便地使用 Java 8 Lambda。不过,需要获取的参数越多,就需要越多的从 InvocationOnMock
的类型转换。
@MyAnnotation
class Foo {
List<String> bar() { ... }
}
Class<?> mockType = mock(Foo.class).getClass();
assert mockType.isAnnotationPresent(MyAnnotation.class);
assert mockType.getDeclaredMethod("bar").getGenericReturnType() instanceof ParameterizedType;
Mockito 会保留加持在类上的注解。
默认关闭。在 classpath 下创建一个 /mockito-extensions/org.mockito.plugins.MockMaker
,并且包含 mock-maker-inline
来开启。
Mockito 还提供了 Jar包 mockito-inline.
Mock final 类型是不兼容 withSettings().serializable()
和 withSettings().extraInterfaces()
的。
注意: java.* 和 native 方法不能mock。
该 mock maker 是基于 Java Agent runtime attachment 设计的。所以,需要兼容的 JVM。
更多内容可以阅读 org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker
重构了API,增加了一堆接口。
tackle double-proxy use case -- double-proxy 是啥玩意?
为集成 Spring Boot 提供新特性。
mock 开始时,可以发出事件通知。
List mock = mock(List.class, withSettings().verificationStartedListeners(new VerificationStartedListener() {
@Override
public void onVerificationStarted(VerificationStartedEvent event) {
System.out.println(event.getMock().getClass().getName());
}
}));
MockitoSession
不清楚改如何使用。
use the org.mockito:mockito-junit-jupiter
artifact.
List mock = mock(List.class);
lenient().when(mock.get(0)).thenReturn("OK");
// all the stubbings on a given mock to be lenient
Foo mockFoo = mock(Foo.class, withSettings().lenient());
没搞懂啥意思。
MockitoFramework.clearInlineMocks()
清理 mock 状态以解决内存泄露问题(memory leaks)。
Mockito (Mockito 3.1.0 API)
Mockito (Mockito 3.6.0 API)
重点关注问题