在做单元测试的时候,我们会发现我们要测试的方法会引用很多外部依赖的对象,比如:(发送邮件,网络通讯,远程服务, 文件系统等等)。 而我们没法控制这些外部依赖的对象,为了解决这个问题,我们就需要用到 Mock 工具来模拟这些外部依赖的对象,来完成单元测试(copy 的)
在看很多人做的 mock 服务都是基于接口返回,无法完全覆盖代码,而且效率也不是很高,
比如这次需要测试功能:获取设备信息和网络信息
代码如下:
public class UserFromSameIp {
private static final Logger LOG = Logger.getLogger(UserFromSameIp.class);
public static List<String> check(int platform, String account, int eventTime) {
List<String> list = new ArrayList<String>();
String ip = null;
if (PlatformCode.isAndroid(platform)) {
BasicDBObject basicDBObject = MgoUtil.getNetWorkBasicDBObject(account, eventTime);
if ( basicDBObject != null && basicDBObject.containsField("clientIp") ) {
ip = basicDBObject.getString("clientIp");
}
} else if (PlatformCode.isH5(platform)) {
ip = MgoUtil.getClientIpH5(account, eventTime);
} else if (PlatformCode.isIOS(platform)) {
ip = MgoUtil.getClientIpIOS(account, eventTime);
}
if (ip == null) {
LOG.warn("account:" + account + ", can't get user ip");
return list;
}
List<String> accounts = MgoUtil.getAccountsByIp(PlatformCode.ANDROID, account, ip);
List<String> accountsH5 = MgoUtil.getAccountsByIp(PlatformCode.H5, account, ip);
List<String> accountsIOS = MgoUtil.getAccountsByIp(PlatformCode.IOS, account, ip);
list.addAll(accounts);
for (int i = 0; i < accountsH5.size(); i++) {
String act = accountsH5.get(i);
if (!list.contains(act)) {
list.add(act);
}
}
for (int i = 0; i < accountsIOS.size(); i++) {
String act = accountsIOS.get(i);
if (!list.contains(act)) {
list.add(act);
}
}
list = FilterNoLoanAccounts.check(list);
return list;
}
}
里面有两个方法需要依赖其他类的方法 getNetWorkBasicDBObject(),getAccountsByIp(),那么 powermock 就可以通过模拟方法返回了
我们只需要做这几个动作就可以了,最终去验证方法是否被调用,从而验证逻辑是否正确
EasyMock.expect(MgoUtil.getNetWorkBasicDBObject(mock_account, mock_eventTime)).andReturn(object);
EasyMock.expect(MgoUtil.getAccountsByIp(PlatformCode.ANDROID, mock_account, mock_ip))
.andReturn(mock_accountList);
EasyMock.expect(MgoUtil.getAccountsByIp(PlatformCode.H5, mock_account, mock_ip)).andReturn(
mock_accountsH5List);
@Test
public void testUserFromSameIpCheck()
{
String mock_account = "13300000000";
int mock_eventTime = 1418192113;
String mock_ip = "127.1.0.1";
BasicDBObject object = new BasicDBObject("clientIp", mock_ip);
List<String> mock_accountList = new ArrayList<String>();
mock_accountList.add("18900000000");
mock_accountList.add("18911111111");
List<String> mock_accountsH5List = new ArrayList<String>();
mock_accountsH5List.add("13300000000");
PowerMock.mockStatic(MgoUtil.class);
PowerMock.mockStatic(MgoManager.class);
EasyMock.expect(MgoUtil.getNetWorkBasicDBObject(mock_account, mock_eventTime)).andReturn(object);
EasyMock.expect(MgoUtil.getAccountsByIp(PlatformCode.ANDROID, mock_account, mock_ip))
.andReturn(mock_accountList);
EasyMock.expect(MgoUtil.getAccountsByIp(PlatformCode.H5, mock_account, mock_ip)).andReturn(
mock_accountsH5List);
EasyMock.expect(MgoUtil.getAccountsByIp(PlatformCode.IOS, mock_account, mock_ip)).andReturn(
new ArrayList<String>());
DBCollection mock_collection = EasyMock.createMock(DBCollection.class);
EasyMock.expect(
mock_collection.distinct(EasyMock.isA(String.class),
EasyMock.isA(BasicDBObject.class))).andReturn(mock_accountList);
MgoManager mock_mgoManager = EasyMock.createMock(MgoManager.class);
EasyMock.expect(MgoManager.getInstance()).andReturn(mock_mgoManager);
EasyMock.replay(mock_collection);
EasyMock.replay(mock_mgoManager);
PowerMock.replayAll();
List<String> returnResult = UserFromSameIp.check(0, mock_account, mock_eventTime);
for (int i = 0; i < mock_accountsH5List.size(); i++)
{
String act = mock_accountsH5List.get(i);
if (!mock_accountList.contains(act))
{
mock_accountList.add(act);
}
}
assertTrue(returnResult.equals(mock_accountList));
EasyMock.verify(mock_collection);
EasyMock.verify(mock_mgoManager);
PowerMock.verifyAll();
}
上述方法都是需要了解代码逻辑,至少能看懂,相对要求比较高,接下来这个测试方法会比较容易,且容易入门
在关键判断语句加上日志,目前大部分都使用的 log4j,这样方面自己通过读取后台日志来判断跑到哪里,假设出问题那是哪里有问题?这样就比较深入了
public static List<String> check(int platform, String account, int eventTime) {
List<String> list = new ArrayList<String>();
String ip = null;
LOG.info("====platform:"+platform); (加的)
if (PlatformCode.isAndroid(platform)) {
BasicDBObject basicDBObject = MgoUtil.getNetWorkBasicDBObject(account, eventTime);
LOG.info("====basicDBObject:"+basicDBObject); (加的)
if ( basicDBObject != null && basicDBObject.containsField("clientIp") ) {
ip = basicDBObject.getString("clientIp");
}
} else if (PlatformCode.isH5(platform)) {
ip = MgoUtil.getClientIpH5(account, eventTime);
LOG.info("====ip:"+ip); (加的)
} else if (PlatformCode.isIOS(platform)) {
ip = MgoUtil.getClientIpIOS(account, eventTime);
}
if (ip == null) {
LOG.warn("account:" + account + ", can't get user ip");
return list;
}
使用 maven install 打包成为 jar 包,发布在服务器,重启,在运行对应的功能就可以查看日志了
查看命令如下:
假设 上诉 check 方法没有调用,可以通过 eclipse 的快捷键跟踪调用者为什么没有执行