JavaMockito的使用
- 我们在写单元测试的时候,有时候不需要去检验某些组件是否正确,我们会默认这些组件正确的情况下测试其他组件,这时候我们可以使用Mocks框架代替其他组件,继续进行单元测试。
- 模拟场景是Mock Spring-data-mongodb的MongoRepository,测试Service
- Mockito官网也有非常完善的文档:
http://site.mockito.org/mockito/docs/current/org/mockito/Mockito.html
在maven工程中添加Mockito依赖
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
测试的Model
@Document(collection = "user")
public class MongoUser {
@Id
private String id;
@Indexed
@Field(value = "name")
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Mock的Repository
public interface MongoUserDao extends MongoRepository<MongoUser, String> {
List<MongoUser> findByName(String name);
}
测试的Service层
@Service
public class UserService {
@Autowired
private MongoUserDao mongoUserDao;
public Observable<List<MongoUser>> findMongoUserByName(String name) {
Observable<List<MongoUser>> ob = Observable.create(observer -> {
try {
List<MongoUser> list = mongoUserDao.findByName(name);
observer.onNext(list);
observer.onCompleted();
} catch (Exception e) {
e.printStackTrace();
observer.onError(e);
}
});
return ob.subscribeOn(Schedulers.io());
}
public Observable<MongoUser> saveMongoUser(MongoUser mongoUser) {
Observable<MongoUser> ob = Observable.create(observer -> {
try {
MongoUser saved = mongoUserDao.save(mongoUser);
observer.onNext(saved);
observer.onCompleted();
} catch (Exception e) {
e.printStackTrace();
observer.onError(e);
}
});
return ob.subscribeOn(Schedulers.io());
}
}
单元测试Mock MongoRepository测试UserService
1.Mock Repository
import static org.mockito.Mockito.*; // 静态导入导入Mockito的内置方法
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestConfig.class)
public class UserServiceMockTest {
@InjectMocks // 将Mock的mongoUserDao注入到Service中
@Autowired
private UserService service;
@Mock //Mock Repository
private MongoUserDao mongoUserDao;
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Before
public void setUp(){
// 在使用@Mock注解时必须初始化Mocks
MockitoAnnotations.initMocks(this);
}
@Test
public void testGetMongoUser() {}
@Test
public void testSaveMongoUser() {}
}
关于上面代码的操作步骤:
# 1. mock repository对象
@Mock //Mock Repository
private MongoUserDao mongoUserDao;
# 2. 将mock的对象注入到service之中
@InjectMocks // 将Mock的mongoUserDao注入到Service中
@Autowired
private UserService service;
# 3. 使用@Mock注解时必须初始化注解
@Before //表示在测试方法调用前执行
public void setUp(){
// 初始化Mock注解
MockitoAnnotations.initMocks(this);
}
# 4. @Rule实现测试单元对异常的判断
@Rule
public ExpectedException expectedException = ExpectedException.none();
2.编写一个基本的测试方法
@Test
public void testGetMongoUser() {
// 1. 先初始化一个我们定义的fake的返回的集合
List<MongoUser> list = new ArrayList<MongoUser>();
MongoUser user = new MongoUser();
user.setId(UUID.randomUUID().toString());
user.setName("user");
list.add(user);
// stubbing mongoUserDao当执行findByName(str)时,anyString()表示传入任意一个String类型的数据
// 就返回我们定义的fake的集合
when(mongoUserDao.findByName(anyString())).thenReturn(list);
// stubbing 当传入一个null参数时,抛出空指针异常
when(mongoUserDao.findByName(null)).thenThrow(
new NullPointerException("username cannot be null"));
//测试service方法
List<MongoUser> listRs = service.findMongoUserByName("user")
.toBlocking().first();
// 验证传入的参数是否是stubbing时matcher的参数
verify(mongoUserDao).findByName(anyString());
// 断言方法返回不为null
Assert.assertNotNull(listRs);
// 断言返回的集合是我们定义的集合
Assert.assertTrue(listRs.containsAll(list));
// 预言下面会抛出NullPointerException
expectedException.expect(NullPointerException.class);
// 预言抛出的异常信息包含 username cannot be null
expectedException.expectMessage("username cannot be null");
// 传入null会抛出异常
service.findMongoUserByName(null).toBlocking().first();
}
3.测试一个保存方法,带参数匹配和返回处理
@Test
public void testSaveMongoUser() {
// 定义一个数组保存save方法生成的id
String[] ids = new String[1];
// stubbing mongoUserDao当执行save方法并传入一个MongoUser对象时
when(mongoUserDao.save(argThat(new ArgumentMatcher<MongoUser>() {
// 匹配传入的参数为一个MongoUser对象
@Override
public boolean matches(Object argument) {
return argument instanceof MongoUser;
}
}))).thenAnswer(new Answer<MongoUser>() {
// 返回mock的保存后的MongoUser对象带ID信息,并将ID保存在ids数组中
@Override
public MongoUser answer(InvocationOnMock invocation)
throws Throwable {
MongoUser user = invocation.getArgumentAt(0, MongoUser.class);
user.setId(ids[0] = UUID.randomUUID().toString());
return user;
}
});
//测试保存方法
MongoUser mongoUser = new MongoUser();
mongoUser.setName("test");
MongoUser saved = service.saveMongoUser(mongoUser).toBlocking().first();
//验证保存对象是否正确
Assert.assertNotNull(saved);
Assert.assertEquals(mongoUser.getName(), saved.getName());
Assert.assertEquals(ids[0], saved.getId());
}