What is mock
Mock
The Chinese translation of Chinese is imitation, simulation, and false. For the testing framework, a simulated/fake object is constructed so that our testing can proceed smoothly.
Mock
During the test, the test is, for some not easy to construct (as HttpServletRequest
must in Servlet
order to construct out of the container) or not easy to get more complex objects (such as JDBC
the ResultSet
target), with a virtual object ( Mock
the object) to create, in order to testing method.
Why use mock testing
Unit testing is to verify the correctness of our code, we focus on the code flow and the correctness of the results.
Contrast real running code, some of which may be external dependencies build steps relatively trouble, if we construct the building in accordance with the rules of external dependencies real code, will greatly increase the operating unit testing, code would also mingled much part of the non-testing The content and test cases are complicated and difficult to understand.
Adopt Mock
framework, we can virtual an external dependencies , focus only on the code of the process and result , truly testing purposes.
Benefits of mock testing framework
- A complex object can be virtualized very simply (for example, an implementation class of an interface can be virtualized);
- You can configure
mock
the behavior of the object; - Can make test cases only focus on the test process and results;
- Reduce the coupling of external classes, systems and dependencies to unit testing.
Mockito process
As shown, using the Mockito
general process is as follows:
-
Create external dependencies of
Mock
the object, and thisMock
is injected into the subject test class in; -
Execute test code ;
-
Check test code has been executed correctly.
Use of Mockito
In Module
the build.gradle
middle add the following:
dependencies {
//Mockito for unit tests
testImplementation "org.mockito:mockito-core:2.+"
//Mockito for Android tests
androidTestImplementation 'org.mockito:mockito-android:2.+'
}
Here is a little explanation:
mockito-core
: A local unit testing , the test code is located in the pathmodule-name/src/test/java/
mockito-android
: For device testing , the need to runandroid
device for testing, the test code is located in the pathmodule-name/src/androidTest/java/
The latest version of mockito-core can be queried in Maven: mockito-core. The latest version of mockito-android can be queried in Maven: mockito-android
Mockito usage example
Common unit test use mockito(mockito-core)
, path:module-name/src/test/java/
Here is an excerpt from the official website Demo
:
Check whether the related behavior of the tuning object is called
import static org.mockito.Mockito.*;
// Mock creation
List mockedList = mock(List.class);
// Use mock object - it does not throw any "unexpected interaction" exception
mockedList.add("one"); //调用了add("one")行为
mockedList.clear(); //调用了clear()行为
// Selective, explicit, highly readable verification
verify(mockedList).add("one"); // 检验add("one")是否已被调用
verify(mockedList).clear(); // 检验clear()是否已被调用
Here mock
a List
(here just to use as Demo
an example, usually to List
create this simple class object, directly and new
a real object can be, without the need for mock
), verify()
whether a test subject in front of the relevant acts have been performed here mockedList
in verify
before has been performed add("one")
and clear()
behavior, it verify()
will pass.
Configuration/Method Behavior
// you can mock concrete classes, not only interfaces
LinkedList mockedList = mock(LinkedList.class);
// stubbing appears before the actual execution
when(mockedList.get(0)).thenReturn("first");
// the following prints "first"
System.out.println(mockedList.get(0));
// the following prints "null" because get(999) was not stubbed
System.out.println(mockedList.get(999));
Here are a few more important points:
when(mockedList.get(0)).thenReturn(“first”)
This sentence Mockito
resolves as follows: When the object mockedList
invocation get()
method, and parameters 0
, the result is returned "first"
, which is equivalent to customize our mock
results of behavior of objects ( mock LinkedList
object mockedList
, specify its behavior get(0)
, the result returned is "first"
).
mockedList.get(999)
Because mockedList
it does not specify get(999)
the behavior, so its results null
. Because the Mockito
underlying principle is to use cglib
dynamically generate a proxy class object , therefore, mock
out of which the object is a substance of the agent , the agent is not configured / acts specified in the case of default returns a null value .
Above Demo
using a static method mock()
to simulate an example, we can also annotate @Mock
also simulate an example:
@Mock
private Intent mIntent;
@Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
@Test
public void mockAndroid(){
Intent intent = mockIntent();
assertThat(intent.getAction()).isEqualTo("com.yn.test.mockito");
assertThat(intent.getStringExtra("Name")).isEqualTo("Whyn");
}
private Intent mockIntent(){
when(mIntent.getAction()).thenReturn("com.yn.test.mockito");
when(mIntent.getStringExtra("Name")).thenReturn("Whyn");
return mIntent;
}
For marked with @Mock
, @Spy
, @InjectMocks
etc. annotated member variable initialization so far there are 2
ways to:
-
To
JUnit
add a test class@RunWith(MockitoJUnitRunner.class)
-
In marked with
@Before
initialization method is called within the method:MockitoAnnotations.initMocks(Object)
The above test case for the @Mock
initialization of member variables notes now have one more way MockitoRule
. Rules MockitoRule
will automatically help us call MockitoAnnotations.initMocks(this)
to instantiate an annotation member variables, we do not need to manually initialized.
Important methods of Mockito
Instantiate virtual objects
// 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.
verify(mockedList).get(0);
-
For all methods,
mock
objects default returnnull
, the original type / types of packaging original default value, or an empty set . For example,int/Integer
type, returns0
, forboolean/Boolean
returnfalse
. -
Behavior configuration (
stub
) can be copied: for example, the usual object behavior has a certain configuration, but the test method can copy this behavior. Keep in mind that behavioral replication may indicate too many potential behaviors. -
Once you have configured behavior, always returns configuration values , regardless of the method has been called many times.
-
The last behavior configuration is more important. When you configure the same method with the same parameters many times, the last time it works.
Parameter matching
Mockito
Parameter object equals()
to verify the parameters are consistent method, when more flexibility is required, matcher parameters may be used:
// 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(argThat(someString -> someString.length() > 5));
Matcher parameters allow a more flexible verification and behavior configuration . More built matcher and custom parameter matcher example refer to: ArgumentMatchers
,MockitoHamcrest
Note: If a parameter matcher is used, then all parameters need to provide a parameter matcher.
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.
Similarly anyObject()
, eq()
this type of matcher does not return matching values. They internal record a match stack and returns a null value (typically null
). This implementation is to match java
the compiler static type safety , the consequences of doing so is that you can not test / configuration method to use outside anyObject()
, eq()
and other methods.
Check times
LinkedList mockedList = mock(LinkedList.class);
// Use mock
mockedList.add("once");
mockedList.add("twice");
mockedList.add("twice");
mockedList.add("three times");
mockedList.add("three times");
mockedList.add("three times");
// Follow 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, atLeastOnce()).add("three times");
verify(mockedList, atLeast(2)).add("three times");
verify(mockedList, atMost(5)).add("three times");
The commonly used methods of checking times are as follows:
Method | Meaning |
---|---|
times(n) | The number of times is n, the default is 1 (times(1)) |
never() | The number of times is 0, which is equivalent to times(0) |
atLeast(n) | At least n times |
atLeastOnce() | At least once |
atMost(n) | Up to n times |
Throw an exception
doThrow(new RuntimeException()).when(mockedList).clear();
// following throws RuntimeException
mockedList.clear();
Check in order
Sometimes for some behaviors, there is a priority, so when we verify, we need to consider the sequence of this behavior:
// A. Single mock whose methods must be invoked in a particular order
List singleMock = mock(List.class);
// Use 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);
// Use 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");
Stub continuous call
For the same way, if we want it in multiple calls respectively return different values, then you can use stub continuous call:
when(mock.someMethod("some arg"))
.thenThrow(new RuntimeException())
.thenReturn("foo");
// First call: throws runtime exception:
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"));
You can also use the following more concise stub continuous call method:
when(mock.someMethod("some arg")).thenReturn("one", "two", "three");
Note: Continuous stub calls require chained calls. If multiple stub configurations of the same method are used, only the last one will work (override the previous stub configuration).
// All mock.someMethod("some arg") calls will return "two"
when(mock.someMethod("some arg").thenReturn("one")
when(mock.someMethod("some arg").thenReturn("two")
Function without return value
For the return type of void
the method, a stub for an alternative form of when(Object)
a function, because the compiler can not claim the presence of parentheses void
method.
For example, a stub for the return type void
is thrown when a method requires a call to an exception:
doThrow(new RuntimeException()).when(mockedList).clear();
// Following throws RuntimeException:
mockedList.clear();
Monitor real objects
We are used before mock
out an object. Thus, when there is no configuration / stub specific behavior, the result will be returned empty type . And if a spy Object ( spy
), then for no stub behavior, it will call the original target method. It can be spy
thought of as a local mock
.
List list = new LinkedList();
List spy = spy(list);
// Optionally, you can stub out some methods:
when(spy.size()).thenReturn(100);
// Use 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");
Note: Because spy is a partial mock, sometimes when (Object) is used, it cannot be stubbed. At this point, you can consider using doReturn() | Answer() | Throw() for stubbing:
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 stubbing
doReturn("foo").when(spy).get(0);
spy
Not the real object of the agent . Instead, it passed over the real object were cloned . So, for the real object of any operation, spy
the object does not perceive. Similarly, for spy
any operation object, it will not affect the real object .
Of course, if mock
for the object locally mock
, by the doCallRealMethod() | thenCallRealMethod()
method it is also possible:
// 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();
Test Driven Development
To behavior-driven development of the format // given // when // then write test cases for testing usage cornerstone comment, this is the Mockito
official method for the preparation of test cases, the test is strongly recommended to use this way to write.
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());
}
Custom error check output information
// 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();
If you exchange experience in software testing, interface testing, automated testing, and interviews. If you are interested, you can add software test communication: 1085991341, and there will be technical exchanges with colleagues.
@InjectMock
Constructors, methods, member variables dependency injection @InjectMock
of the annotation, Mockito
checks the class constructors , methods , or member variable , depending on their type automatically mock
.
public class InjectMockTest {
@Mock
private User user;
@Mock
private ArticleDatabase database;
@InjectMocks
private ArticleManager manager;
@Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
@Test
public void testInjectMock() {
// Calls addListener with an instance of ArticleListener
manager.initialize();
// Validate that addListener was called
verify(database).addListener(any(ArticleListener.class));
}
public static class ArticleManager {
private User user;
private ArticleDatabase database;
public ArticleManager(User user, ArticleDatabase database) {
super();
this.user = user;
this.database = database;
}
public void initialize() {
database.addListener(new ArticleListener());
}
}
public static class User {
}
public static class ArticleListener {
}
public static class ArticleDatabase {
public void addListener(ArticleListener listener) {
}
}
}
Member variable manager
of type ArticleManager
, it's Farewell identified above @InjectMocks
. This means mock
that manager
, Mockito
you need to automatically mock
the ArticleManager
required configuration parameters (ie: user
and database
), finally mock
get an ArticleManager
assignment to manager
.
Parameter capture
ArgumentCaptor
Allow verify
time to obtain the method parameter content , which enables us in the testing process can pair calls method parameters were captured and tested .
@Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
@Captor
private ArgumentCaptor<List<String>> captor;
@Test
public void testArgumentCaptor(){
List<String> asList = Arrays.asList("someElement_test", "someElement");
final List<String> mockedList = mock(List.class);
mockedList.addAll(asList);
verify(mockedList).addAll(captor.capture()); // When verify,you can capture the arguments of the calling method
final List<String> capturedArgument = captor.getValue();
assertThat(capturedArgument, hasItem("someElement"));
}
Limitations of Mocktio
- Not
mock
a static method; - Not
mock
builder; - Can not
mock
equals()
andhashCode()
method
above is the entire contents of the above Benpian want to help you, have helped to friends welcome thumbs up, comment.