Mockito介绍和使用
一、什么是mockito? mockito有什么作用?
Mockito是一个mocking框架,让你用简单干净的API写漂亮的测试代码。Mockito不会让你混乱,因为测试代码具有非常好的可读性,Mockito可以创建纯净的环境来进行代码功能的验证。
如上图所示,ServiceA中的Func1调用了另外一个ServiceB里的Func2以及Dao层1和2两个类中的CRUD的方法,如果我们想对ServiceA进行单元测试,首先需要把serviceB和Dao1,Dao2三个类的实例构建出来,并且在测试ServiceA的Func1时,肯定会执行ServiceB中的Func2和Dao1和2两个类中的CRUD的方法,如果这三个方法中出错,也会导致我们的单元测试异常,这不是我们的本意,我们只需要测试ServiceA中的Func1功能是否正确,另外的三个方法有专门的测试类会对他们进行测试。由此,我们引入了mockito框架。
mock对象就是在调试期间用来作为真实对象的替代品。
Mockito 是用于生成模拟对象或者直接点说,就是”假对象“的工具。一般通常的做法就是联合 JUnit + Mockito 来进行测试。
二、简单使用
Maven依赖:
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.6.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.6.5</version>
<scope>test</scope>
</dependency>
Java代码:
import static org.mockito.Mockito.*;
// mock creation
List mockedList = mock(List.class);
// using mock object - it does not throw any "unexpected interaction" exception
mockedList.add("one");
mockedList.clear();
// selective, explicit, highly readable verification
verify(mockedList).add("one");
verify(mockedList).clear();
三、更多…
- mock()/@Mock: 在需要Mock的属性上标记@Mock注解,然后@RunWith(MockitoJUnitRunner.class)或者在@Before方法中显示调用MockitoAnnotations.initMocks(this);生成Mock类即可
- spy()/@Spy: 部分的mocking,@Mock是针对接口生成Mock类,所以我们是没法调用到真实的实现类的方法。可以使用@Spy注解标注属性,并且标注@Resource注解让Spring注入真实实现类,那么Mockito就会自动生成Spy类。Spy类就可以满足我们的要求。如果一个方法mock了返回值或者异常,那么就会按照mock的方式被调用执行;如果一个方法没被mock,那么调用的就是真实类的方法。
- @InjectMocks: 自动的将带有@Mock和@Spy注解的属性注入到被测试类中
- verify(): 检查方法是否被调用
- 参数匹配器:Matchers类内加了有很多参数匹配器anyInt(),anyString(),anyMap()…..Mockito类继承于Matchers,Stubbing时使用内建参数匹配器。如果使用参数匹配器,那么所有的参数都要使用参数匹配器,不管是stubbing还是verify的时候都一样。
四、复杂示例
- Dao层
@Repository
public class OrderDao {
public Order getOrder(int irderId){
throw new UnsupportedOperationException("Fail is not mocked!");
}
}
2.Service层
@Service
public class PriceService {
public int getActualPrice(Item item){
throw new UnsupportedOperationException("Fail is not mocked!");
}
public int calculatePriceForOrder(Order order){
int orderPrice = 0;
for (Item item : order.getItems()){
orderPrice += getActualPrice(item);
}
return orderPrice;
}
}
@Service
public class OrderService {
@Autowired
private PriceService priceService;
@Autowired
private OrderDao orderDao;
public int getOrderPrice(int orderId){
Order order = orderDao.getOrder(orderId);
return priceService.calculatePriceForOrder(order);
}
}
3.测试Service类
public class OrderServiceTest {
private static final int TEST_ORDER_ID = 15;
private static final int TEST_SHOES_PRICE = 2;
private static final int TEST_SHIRT_PRICE = 1;
@InjectMocks
private OrderService testingObject;
@Spy
private PriceService priceService;
@Mock
private OrderDao orderDao;
@BeforeMethod
public void initMocks(){
MockitoAnnotations.initMocks(this);
}
@Test
public void testGetOrderService(){
Order order = new Order(Arrays.asList(Item.SHOES, Item.SHIRT));
Mockito.when(orderDao.getOrder(TEST_ORDER_ID)).thenReturn(order);
//notice different Mockito syntax for spy
Mockito.doReturn(TEST_SHIRT_PRICE).when(priceService).getActualPrice(Item.SHIRT);
Mockito.doReturn(TEST_SHOES_PRICE).when(priceService).getActualPrice(Item.SHOES);
//call testing method
int actualOrderPrice = testingObject.getOrderPrice(TEST_ORDER_ID);
Assert.assertEquals(TEST_SHIRT_PRICE + TEST_SHOES_PRICE, actualOrderPrice);
}
}