Java的Mockito测试如何使用
由于种种原因,我们暂时无法从数据库、或者依赖其他系统的接口中,无法获取到测试数据,我们难以对自己的接口顺利进行测试,所以我们可以使用Mockito测试框架来Mock所需要的数据,测试我们的代码。
简单方法使用(无其他系统依赖情况)
1.测试方法是否被调用
@Test
public void verifyAccount(){
Account mockAccount = mock(Account.class);
mockAccount.setAge(1);
mockAccount.setName("单边里");
//verify方法来确认方法是否调用了setAge(),setName()方法
verify(mockAccount).setAge(1);
verify(mockAccount).setName("单边里");
}
2.Mock测试返回值
@Test
public void returnTest(){
Account mockAccount = mock(Account.class);
//当调用getId()方法的时候,thenReturn方法mock自定义返回值
when(mockAccount.getId()).thenReturn(2L);
//当调用getId()方法的时候,thenThrow方法mock抛出自定义异常
when(mockAccount.getName()).thenThrow(new NoSuchElementException());
System.out.println(mockAccount.getId());
System.out.println("-------");
System.out.println(mockAccount.getName());
}
结果:
2
-------
java.util.NoSuchElementException
at com.test.AccountTest.returnTest(AccountTest.java:43)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...
3.验证参数
账户类中添加一个简单生成密码的方法:入参为Long类型
public String setPasswordById(Long id){
this.password=this.id+this.name+id;
return this.password;
}
Mock测试参数:
@Test
public void matchTest(){
Account mockAccount = mock(Account.class);
//anyLong()方法测试入参是否是所需要类型
when(mockAccount.setPasswordById(anyLong())).thenReturn("单边里新密码");
System.out.println(mockAccount.setPasswordById(10L));
}
结果:
单边里新密码
4.验证方法调用次数和顺序
@Test
public void orderTest(){
Account mockAccount = mock(Account.class);
mockAccount.setName("唐寅");
mockAccount.setName("赵越");
mockAccount.setName("白均可");
//times方法验证次数
verify(mockAccount,times(3)).setName(anyString());
//inOrder验证执行顺序,参数可传入多个对象
InOrder inOrder = inOrder(mockAccount);
inOrder.verify(mockAccount).setName("唐寅");
inOrder.verify(mockAccount).setName("赵越");
inOrder.verify(mockAccount).setName("白均可");
}
5.监控真实对象、装扮其方法
@Test
public void spyTest(){
//创建真实对象
Account account = new Account(1L,"唐寅");
//监控此对象
Account spy = spy(account);
//装扮getName方法
when(spy.getName()).thenReturn("田家豪");
System.out.println(spy.getId());
System.out.println(spy.getName());
}
//结果:
1
田家豪
分布式环境使用(有其他系统依赖情况)
如微服务架构下,多服务直接需要交互,如果依赖对方的代码还未开发完成,我们便可以Mock他们的接口来使用。如需要依赖对方的用户系统,根据id查询User对象,获取name,来set到我们的Account对象中:
所依赖的系统:
模型类:
//其他系统内容
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User {
private int id;
private String name;
}
//其他系统中的接口,模拟还未完成,返回null
@Service
public class UserServiceImpl implements UserService {
@Override
public User findUserById(int id) {
return null;
}
}
本系统:
模型类:
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Account {
private int id;
private String name;//name数据需要依赖用户系统查询
private String address;
}
接口:
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private UserService userService;
@Override
public Account findAccountById(int id) {
return new Account(id,userService.findUserById(id).getName(),"李家亚");
}
}
Mock单元测试
@RunWith(MockitoJUnitRunner.class)
public class MockTest {
@InjectMocks
private AccountService accountService = new AccountServiceImpl();//自身接口
@Mock
private UserService userService;//依赖其他还未完成的接口
@Test
public void method(){
//因为对方还未完成接口,所以我们假设调用其接口会返回user,是自定义的
User user = new User(2,"唐寅");
Mockito.when(userService.findUserById(Mockito.anyInt())).thenReturn(user);
//我们断言一下期望name是否和实际本系统方法返回对象中的name相同
Assert.assertEquals("唐寅",accountService.findAccountById(2).getName());
}
}
//结果,绿色通过