白盒测试 基于 PowerMock 的单元测试&基于代码的后台测试

tttttttttggggg · 2017年12月13日 · 800 次阅读

PowerMock 介绍

在做单元测试的时候,我们会发现我们要测试的方法会引用很多外部依赖的对象,比如:(发送邮件,网络通讯,远程服务, 文件系统等等)。 而我们没法控制这些外部依赖的对象,为了解决这个问题,我们就需要用到 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 的快捷键跟踪调用者为什么没有执行

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册