测试老兵 关于埋点测试和平台化处理方案

飞狐 · November 24, 2018 · Last by 飞狐 replied at March 07, 2019 · 3009 hits

最近忙在项目里面,在项目后期,有个埋点测试,服务端加客户端的点,差不多有50个,假设纯肉眼测试,那简直就是崩溃,因此前期先简单的做了数据解析及数据结构解析,后期准备平台化处理

以目前我们使用的神策打点举例,打点包含 事件,事件属性,预置属性
安卓和ios打同一个点的时候,若数据类型不一致,一旦一端入库之后,另一端肯定入不了库,因此需要检验数据类型

后续给大家补上关键代码处理

说下思路及目前做法:

1.由于我们这边等于在入库前做一次数据检查,但我们不需要存储数据,所以与客户端约定,在测试环境,客户端把打点数据发送到nginx,由nginx转发到神策服务器
2.已经配置nginx,把客服端的请求日志打印出来,所以只需解析access.log日志,
3.过滤出要处理的数据,urldecode解码,base64解密,gzip解压缩,得到json数据
4.套用我之前文章中的格式解析,达到格式检验,其他就是自己写个方法解析数据。检验自己预期得到的数据

平台化思路:

1.打点时间按照指定数据格式文档上传服务器,自动生成模板事件格式,这个方案能解决客户端希望的格式检验问题
2.上传access.log日志到服务器
3.运行上述核心方法检验,输出测试结果

ps:服务端打点没有特意说到,我们这边服务端的打点处理更加简单,服务端代码默认是按照神策打点日志格式写到本地磁盘,把神策服务默认从该磁盘读取处理,因此只需把日志拉出来按照上述方式处理即可

Nginx配置

解密

   @Test
public void testDecode1() throws IOException{
String value = "H4sIAAAAAAAAE%2B2Y7W8bNRzH%2FxenL5PK5%2FM9OO%2FyNIRgMCmb9mJClntxEqsX%2B%2BTztaqqSt1LYLANaUgIELA3IBDiDdLQpok%2FZqRZ%2FwvspCU5LS1dq0Vl9F6dfmf%2FHj%2F%2BysmdXWDEiIO6F2BEMPZ8GHphFVCjWbJJRQ%2FUoxBCLwgIrgK%2BxaUBdbDWyLKuYdoAu7KfFvmQlr0EXoxQFfREboRMzNQPCIJ2qwlxu0YaIaphHDdqpENatdhvRjBowmuYeNZhplXGtRE8B%2FVdsNbjWyLhMw8exp1mSEitEwakhjuwVWu22o1aFMYYkqjT9AiyHtZUTre4zoWSbhNah%2BvO8VrCtBZcW9tff%2Fw6%2Fvr55Mdn409%2Bmm2wRvFh172LnPaFzg3tsR1Q77M059aaJ5pzSYdcDIa2BbGH5sZt0TNDUPejwNpGqsdT5%2B3GUEnuwarvnEputpXepGYns20C%2BB1nTMXGPCzLsoWkXc7QmUdMFn2WmEJPE7eNT7mzb4u%2BmGdnPS1WvB6vI69Uy2w8x8s1z4sRp32tRnTDznmgVSFtg40u%2BF4VHCU5RcB6maa5OwvS44YJV16Xy1zpvCFZumNEknfb71UqtoZUJMzYNNqi1%2BSJGvFGYsQWr1fsA07J9Cy9cHtH3AyVYyGxfQZ7e9VXACZhgEoA%2B5j4gYUYzQHmNGMDTo8rvIQM36AfNK537PprQg64Pvzi8eTB7%2FTF%2FoPxd08nP%2By%2F2H84%2BerZ%2BPmjyaN7h98%2BvjD0S%2FE%2B9SScAfrSTJeegItA7%2FbmqtCJc9efdolmgkl1ImZnRPvmzY7DpGVR3rzOpAVFVyrG0Ck8tK%2F0jP1%2F0L8tzLDOjNFiozA8Xx3qGCLsl1DHMIQ%2BjpyCL2r1tJQVcM5TPnI9SpQ0s%2BgHH3968M3T8Z%2B%2FHHz2ZAasq27lmv4fxPs4EcncsCyUt3nq9LRle6tVmtqt1XnHj8LeerdZGGOjXfgIvBKtUlkh1zGKSlx7oSUEBYj4b5eGHx2P%2Bwtn4%2F%2FG%2BZWMY2LpLuFOIncLj2F8WWT85edPxve%2FPPz53svf7k6%2Bv3ul4efS8Gnk99VAyJWI%2BLJwK1TxwENxWcXjCBJoP%2BHLgvXVjeSK5jPTHJHyXdtDIY4j%2B8tygeauGMhb2WuxjKBHMIqhfd7onx%2F%2FCt%2FJ3J4TwDI8S3E8ibtTJrWMH6WF5YKlr6UOi9DR3A6uyM53lUgdlG%2FsuvDR3wNnZBqjEwAA";
String value1 = URLDecoder.decode(value);
System.out.println(value1);
System.out.println(new String(uncompress(Base64Coder.decode(value1))));
}


public static byte[] uncompress(byte[] bytes) {
if (bytes == null || bytes.length == 0) {
return null;
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
try {
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
} catch (IOException e) {
// ApiLogger.error("gzip uncompress error.", e);
e.printStackTrace();
}

return out.toByteArray();
}

输出结果:

数据校验

    /**
* 检查原始数据是否包含基础checkList,失败则添加到结果
* @param sourceInfo
* @param checkList
* @param event
* @return
*/

public JSONObject checkResult(JSONArray sourceInfo,Map<String,String> checkList,String event){
JSONObject result = new JSONObject();
Set<String> eventSet = new HashSet<String>();

JSONObject formatResult = new JSONObject();
for(int i = 0 ;i < sourceInfo.size(); i++){
JSONObject tempObj = JSONObject.fromObject(sourceInfo.get(i));
String eventValue = tempObj.getString("event");

if(eventValue.startsWith("$")){
continue;
}

if(StringUtils.isNotEmpty(eventValue)&& event.equals(eventValue)){
JSONObject propertiesObj = tempObj.getJSONObject("properties");

String eventInfo = "";
if(propertiesObj.containsKey("$os")) {
//拼接 Event事件 名称: os+event
eventInfo = propertiesObj.getString("$os") + "_" + event;
eventSet.add(eventInfo);
// //比对JSON
// formatResult.put(eventInfo,DiffMethod.diffFormatJson(propertiesObj,DEFAULT_PROPERTIES_JSON));
}

StringBuffer resultInfo = new StringBuffer();
StringBuffer formatResultInfo = new StringBuffer();
for (String key:checkList.keySet()){
if(!propertiesObj.containsKey(key)){
if(propertiesObj.containsKey("$os")) {
resultInfo.append("操作系统:[" + propertiesObj.getString("$os") + "]");
}
resultInfo.append("预期应有基础属性值:" + key + ",而实际不包含这个值");

}

if(propertiesObj.containsKey(key)){
String expectType = checkList.get(key);
String resultType = DiffMethod.getTypeValue(propertiesObj.get(key));
System.out.println(eventInfo + "--实际值:" + key + ":::" + propertiesObj.get(key));
if(!resultType.equalsIgnoreCase(expectType)){
System.out.println("预期:" + expectType);
System.out.println("实际:" + resultType);
formatResultInfo.append(key + "预期类型:" + expectType + ",实际类型:" + resultType);
}
}

}
result.put(eventInfo,resultInfo.toString());
result.put(eventInfo + "Format",formatResultInfo.toString());

}
}

return result;
}

方法调用

/**
* 测试指定事件
*/

@Test
public void testPointEvent(){
String filePath = "/nglog/dd.txt";
JSONArray sourceLog = scLogAnalyseApi.readLogAsList(filePath);
//测试自定义属性
Map<String,String> customPropertiesList = Maps.newHashMap();
String eventName = "PIANO_STUDENTS_ATTEND_CLASS";
customPropertiesList.put("app_source","String");
customPropertiesList.put("HANDLE_OBJECT","String");
customPropertiesList.put("TRAIN_GOODS_NAME","String");
customPropertiesList.put("COURSE_ITEM_TEACHER_USER_NICK","String");
JSONObject analyseResult = checkResult(sourceLog,customPropertiesList,eventName);
System.out.println(analyseResult);
}
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 10 条回复 时间 点赞
飞狐 关闭了讨论 24 Nov 14:00
飞狐 重新开启了讨论 24 Nov 14:00

已经mark,加油哦!

还好 我们的埋点都是开发自测的。。。

恒温 回复

其实埋点我想丢给产品测试,都是产品跟运营在看😀

飞狐 回复

我们因为要自己洗数据,所以还要关心下,其实大部分应该是数据来做

我们都是产品测试的,测试没人力,产品去大数据那边拿埋点数据。

恒温 回复

大公司分工比较明确,我这边小公司,很多时候一旦出问题都是直接找测试,所有还是要经过测试这一关

magicyang 回复

我们没大数据部门😄

我们做了一个实时上报的工具,可以实时查看终端的上报。验证终端是否上报并上报字段是否正确,如果是OK的,然后再到大数据查询是否入库成功。

qiangqing2018 回复

你好,实时上报是什么意思?如何验证终端是否上报并检查上报字段是否正确呢?因为打点事件非常多。

飞狐 #12 · March 07, 2019 作者

猜测只是打印出神策相关日志。根据打点要求,肉眼比对

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up