标签:mockito
使用Mockito来Mock对象
有两种方法来mock对象,1)使用静态方法: mock()
;2) 使用注解:@Mock
。
mock()
@Test
public void givenCountMethodMocked_WhenCountInvoked_ThenMockedValueReturned() {
UserRepository localMockRepository = Mockito.mock(UserRepository.class);
Mockito.when(localMockRepository.count()).thenReturn(111L);
long userCount = localMockRepository.count();
Assert.assertEquals(111L, userCount);
Mockito.verify(localMockRepository).count();
}
-
@Mock
- 采用
@Rule
注解来调用MockitoAnnotations.initMocks(this)
- 采用
@RunWith(MockitoJUnitRunner.class)
- 采用
//实例1
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");
}
}
//实例2
@RunWith(MockitoJUnitRunner.class)
public class MockAnnotationUnitTest {
@Mock
UserRepository mockRepository;
@Test
public void givenCountMethodMocked_WhenCountInvoked_ThenMockValueReturned() {
Mockito.when(mockRepository.count()).thenReturn(123L);
long userCount = mockRepository.count();
Assert.assertEquals(123L, userCount);
Mockito.verify(mockRepository).count();
}
}
Configuring mocks
- "when thenReturn"和"when thenThrow
- "doReturn when"和"doThrow when"
The
doReturn(…).when(…).methodCall
call chain works similar towhen(….).thenReturn(….)
. It is useful for mocking methods which give an exception during a call.
使用Spy来包装java对象
@spy
或者spy()
方法被用来包装一个真实的对象。
spy()
@Test
public void whenNotUseSpyAnnotation_thenCorrect() {
List spyList = Mockito.spy(new ArrayList());
spyList.add("one");
spyList.add("two");
Mockito.verify(spyList).add("one");
Mockito.verify(spyList).add("two");
assertEquals(2, spyList.size());
Mockito.doReturn(100).when(spyList).size();
assertEquals(100, spyList.size());
}
@spy
@Spy
List spiedList = new ArrayList();
@Test
public void whenUseSpyAnnotation_thenSpyIsInjectedCorrectly() {
spiedList.add("one");
spiedList.add("two");
Mockito.verify(spiedList).add("one");
Mockito.verify(spiedList).add("two");
assertEquals(2, spiedList.size());
Mockito.doReturn(100).when(spiedList).size();
assertEquals(100, spiedList.size());
}
在这个例子中,使用真实的方法spiedList.add()
来给spiedList
增加元素。
verify的用途
import static org.mockito.Mockito.*;
@Test
public void testVerify() {
// create and configure mock
MyClass test = Mockito.mock(MyClass.class);
when(test.getUniqueId()).thenReturn(43);
// call method testing on the mock with parameter 12
test.testing(12);
test.getUniqueId();
test.getUniqueId();
// now check if method testing was called with the parameter 12
verify(test).testing(ArgumentMatchers.eq(12));
// was the method called twice?
verify(test, times(2)).getUniqueId();
// other alternatives for verifiying the number of method calls for a method
verify(test, never()).someMethod("never called");
verify(test, atLeastOnce()).someMethod("called at least once");
verify(test, atLeast(2)).someMethod("called at least twice");
verify(test, times(5)).someMethod("called five times");
verify(test, atMost(3)).someMethod("called at most 3 times");
// This let's you check that no other methods where called on this object.
// You call it after you have verified the expected method calls.
verifyNoMoreInteractions(test);
}
@injectMock
若某个class中有依赖的属性或者方法,在创建此class实例时,使用@InjectMocks
来将mock注入。例如,我们有这样一个类:
public 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());
}
}
这个类可通过Mockito来被创建,它的依赖也能被mock填充。
@RunWith(MockitoJUnitRunner.class)
public class ArticleManagerTest {
@Mock ArticleCalculator calculator;
@Mock ArticleDatabase database;
@Mock User user;
@Spy private UserProvider userProvider = new ConsumerUserProvider();
@InjectMocks private ArticleManager manager;
@Test public void shouldDoSomething() {
// calls addListener with an instance of ArticleListener
manager.initialize();
// validate that addListener was called
verify(database).addListener(any(ArticleListener.class));
}
}
捕获参数
ArgumentCaptor类允许在验证期间访问方法调用的参数。采用@Captor
来实现。
import static org.hamcrest.Matchers.hasItem;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import java.util.Arrays;
import java.util.List;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
public class MockitoTests {
@Rule
public MockitoRule rule = MockitoJUnit.rule();
@Captor
private ArgumentCaptor> captor;
@Test
public final void shouldContainCertainListItem() {
List asList = Arrays.asList("someElement_test", "someElement");
final List mockedList = mock(List.class);
mockedList.addAll(asList);
verify(mockedList).addAll(captor.capture());
final List capturedArgument = captor.getValue();
assertThat(capturedArgument, hasItem("someElement"));
}
}
上述代码首先创建了一个参数列表,然后mock了一个List对象通过调用addAll
函数来将参数添加到mockedList
中。使用verify
来验证mockedList
调用addAll
函数时,利用captor
捕捉参数。captor
是一个ArgumentCaptor
实例,存储的是List
类型的数据。最后,通过captor.getValue()
来获得捕获的参数。
mock final类
java中的final关键字可以用来修饰变量、方法和类。final修饰变量,此变量是不能被修改的;final修饰方法,此方法不能被重写的(override);final修饰类后,此类不能被继承。下面给出一个例子来说明如何mock final类:
final class FinalClassDemo {
public final String finalMethod() {
return "something";
}
}
@Test
public final void mockFinalClassTest() {
FinalClassDemo instance = new FinalClassDemo();
FinalClassDemo mock = mock(FinalClassDemo.class);
when(mock.finalMethod()).thenReturn("other things");
assertNotEquals(mock.finalMethod(), instance.finalMethod());
}
注意到,在对final类进行测试时,测试方法也是final的。
以前遇到过使用mock的实例
TWU期间的SpingBoot的Workshop,我们在Spring项目中用到类Mockito。但是,对于Spring项目,我们使用@MockBean
注解来给Spring应用添加mock对象。下面的例子是Spring应用中,对于controller层进行测试的测试代码。由于controller层和service层存在依赖,因此需要mock service层的对象来进行测试。
@RunWith(SpringRunner.class)
@WebMvcTest(ProductController.class)
public class ProductControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private ProductService productService;
@Test
public void should_return_201_and_location_when_creating_product() throws Exception {
//given
Product product = new Product();
product.setName("ice peak");
Product createdProdcut = new Product();
createdProdcut.setId("id1");
createdProdcut.setName("ice peak");
when(productService.create(refEq(product))).thenReturn(createdProdcut);
mockMvc.perform(post("/products")
.accept(MediaType.APPLICATION_JSON)
.param("name","ice peak"))
.andExpect(status().isCreated())
.andExpect(header().string("location",containsString("/products/id1")));
}
}
可以看到,在spring中我们使用注解@RunWith(SpringRunner.class)
。对于service层的mock,使用的注解是@MockBean
。
注意到,我们使用mockMvc
来进行测试。