接口测试 金融类数据测试与监控实践

编程梦想佳 · 2017年08月08日 · 最后由 编程梦想佳 回复于 2017年08月13日 · 3014 次阅读

问题的提出

今天我要分享的是 如何测试和监控实时接口

金融类接口数据的因为业务性比较强, 就像股票,每天的价格都是实时的,除非特殊原因,例如停牌,价格才不会变动。 所以原来的的测试,基本都是要靠着准确的时间去测试,如股票开盘是 9:30 , 11:30 收盘。特别是行情系统改动了一点,很多时候,测试是非常辛苦的。 特别是如果实时数据有问题,那么将导致今天的数据不准确,而且验证又是需要这样重复的流程。而且这个接口是不能出错的,不然行情数据是不对的。如果用户直接索赔,那就尴尬了。

那么有没办法解决这种问题呢。 为了妹子的笑容,我牺牲点脑细胞还是可以的。

我要测试的就是这样子的数据

问题的解决过程

第一次尝试 :

好吧,第一次我就去尝试了下,结果第一次手动测试,我就错过了时间。。。。

第二次尝试:

需求:

通过接口比对公司的接口和新浪接口是否一致

实现:

testng +HttpClient 调用我公司行情接口 +新浪行情接口 进行比对

接口说明

Sina 股票数据接口
以大秦铁路(股票代码:601006)为例,如果要获取它的最新行情,只需访问新浪的股票数据接口:
http://hq.sinajs.cn/list=sh601006
这个 url 会返回一串文本,例如:
var hq_str_sh601006="大秦铁路, 27.55, 27.25, 26.91, 27.55, 26.20, 26.91, 26.92,
22114263, 589824680, 4695, 26.91, 57590, 26.90, 14700, 26.89, 14300,
26.88, 15100, 26.87, 3100, 26.92, 8900, 26.93, 14230, 26.94, 25150, 26.95, 15220, 26.96, 2008-01-11, 15:05:32";

字段 0:” 大秦铁路”,股票名字;
字段 1:” 27.55″,今日开盘价;
字段 2:” 27.25″,昨日收盘价;
字段 3:” 26.91″,当前价格;
等等 ..........

用例管理

用例的设计 我采用 yaml 进行管理

  • 比特币类型
testcase:
    - base_url: http://api.btctrade.com/api/ticker
      type: BTC
      param: coin=${coinType}

参数化放在 execl 中

coinType
eth
btc
doge
  • 股票类型
testcase:
    - base_url: http://hq.sinajs.cn/
      type: BTC
      param: list=${fullcode}

参数化放在 execl 中

fullcode
sh000001
sz300005
数据比较

我司数据接口返回的是 json 数据,也是如上接口的数据一样,只是返回的是 json 数据
两个接口进行比对,如果数据相同就是通过的。

testng 中使用 assertEquals 方法:判断是否相等,Object 类型的对象需要实现 haseCode 及 equals 方法。这个就不说明了, 因为都是== 啊,Equals

第三次尝试:

需求:

为了满足测试一整天的接口的准确性 时间段 每天 9:30 ---23:00 每 5 秒调用一次

实现 :

这次的实现使用 HttpClient + webmagic + javamail +Quartz

因为这个爬虫的代码逻辑比较复杂点 所以我重点说明:

首先通过 Quartz 启动定时任务

QuartzManager.addJob("btctrade",
                BtcTradeJob.class.getName(), "*/5 * 7-23 * * ?"); //7-23点获取数据 ,定时5秒刷新接口
QuartzManager.addJob("次新股",
                NewStockPlateJob.class.getName(), "*/5 * 9-15 ? * MON-FRI");//9点15开始 定时5秒刷新接口

定制获取数据的 job,以比特币为例子

package com.mj.job;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import us.codecraft.webmagic.Spider;

import com.mj.processor.BtcProcessor;
import com.mj.processor.BtcTradeProcessor;

public class BtcTradeJob implements Job {
    // BTC:http://api.btctrade.com/api/ticker?coin=btc
    // ETH:http://api.btctrade.com/api/ticker?coin=eth
    // LTC:http://api.btctrade.com/api/ticker?coin=ltc
    // DOGE:http://api.btctrade.com/api/ticker?coin=doge
    // YBC:http://api.btctrade.com/api/ticker?coin=ybc
    public void execute(JobExecutionContext arg0) throws JobExecutionException {
        Spider.create(new BtcTradeProcessor())
                .addUrl("http://api.btctrade.com/api/ticker?coin=btc",
                        "http://api.btctrade.com/api/ticker?coin=eth",
                        "http://api.btctrade.com/api/ticker?coin=ltc",
                        "http://api.btctrade.com/api/ticker?coin=doge",
                        "http://api.btctrade.com/api/ticker?coin=ybc")
                .thread(2)
                .run();
    }
}

通过 Processor 进行对比

package com.mj.processor;

import java.util.Date;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.mj.activity.BtcServer;
import com.mj.common.cache.CacheManager;
import com.mj.model.BtcModel;
import com.mj.model.NotifyModel;
import com.mj.util.date.VeDate;
import com.mj.util.mail.MailUtil;

import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.processor.PageProcessor;

public class BtcTradeProcessor implements PageProcessor {
    private static final Logger logger = LoggerFactory
            .getLogger(BtcTradeProcessor.class);
    // 部分一:抓取网站的相关配置,包括编码、抓取间隔、重试次数等
    private Site site = Site.me().setRetryTimes(5).setSleepTime(1000);

    // process是定制爬虫逻辑的核心接口,在这里编写抽取逻辑
    public void process(Page page) {
        // TODO Auto-generated method stub
        // page.setSkip(true);
        if (page != null) {
            logger.debug(page.getJson().toString());
            // MailUtil.mail("数据", page.getJson().toString());
            BtcModel model = JSON.parseObject(page.getJson().toString(),
                    BtcModel.class);
            if (model != null) {
                model.type = page.getRequest().getUrl().replace("http://api.btctrade.com/api/ticker?coin=", "btctrade_");
                logger.debug(model.toString());
                if (CacheManager.getInstance().getCache(model.type) == null) {
                    CacheManager.getInstance().putCache(model.type,
                            "20170101010101");
                }

                           //这里忽略了公司的对比代码
                           ....
                if (不通过就发送邮件) {
                        CacheManager.getInstance().putCache(model.type,
                                nowStr);
                        NotifyModel notifyModel = new NotifyModel();
                        notifyModel.head = model.type + "最低价";
                        notifyModel.body = " 最新 " + model.last + " 最低 "
                                + model.low + " 最高 " + model.high ++nowStr+出现数据不一致;
                        MailUtil.mail(notifyModel.head, notifyModel.body);
                }
            }
        }
    }

    public Site getSite() {
        return site;
    }

}

用例的管理想法和第二次尝试一样, 用 execl 和 yaml 双剑客。也就不累赘说明了。

共收到 15 条回复 时间 点赞

请问下楼主,金融类的接口这么搞,那普通的那些互联网产品也有必要做接口监控吗

@shayang888 金融类的接口要求 准确,实时, 普通的互联网应该不用。 如果是测试大数据类型的,也可以把数据存储起来,做对比。 不用像我这样子的。
我这样子做的原因是

  1. 省掉了存储的逻辑,可以偷懒下。
  2. 可以马上知道自己的接口和其他同类型的公司数据不一致了。

金融类的数据是不能出错的,就为了这个,我 搞了 redis 集群用来存储行情数据,而且是 2 套,防止同事出错。

对比算法怎么写的?

@lucasluo 你这个问题提得好, 因为公司的算法,我不好公布,不过我可以补上自己写的 demo,中午吃饭补上

监控这块只看到作者是做不同接口数据的对比,除此之外还有其他的吗

大家用什么 markdown 客户端呢, 在网页写很辛苦哦,有没好的推荐客户端呢

赞赞赞

谢谢分享,点赞

楼主使用的莫非是东方财富终端?

@CwXwWw 是用东方财富的图, 这都被你发现了

有没有仿真环境的接口,可以对比测试的?

—— 来自 TesterHome 官方 安卓客户端

新浪和东方财富有仿真环境期货行情数据接口提供么?

—— 来自 TesterHome 官方 安卓客户端

@lion 有的,公开的 api 有 新浪和 yahoo,你也可以抓取网页上的接口,我也是这么干的

@Lihuazhang 谢谢你的推荐

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