今天我要分享的是 如何测试和监控实时接口
金融类接口数据的因为业务性比较强, 就像股票,每天的价格都是实时的,除非特殊原因,例如停牌,价格才不会变动。 所以原来的的测试,基本都是要靠着准确的时间去测试,如股票开盘是 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 双剑客。也就不累赘说明了。