在第三篇中,关于前端页面的设计,陆续有网友给出了意见,其中有推荐一个工具:Pingendo,适合自主开发页面,有兴趣的网友可以自行体验下。
和大多数的云测试平台一样,我们希望实现的效果是:将被测 apk、ipa(甚至测试用例) 上传,后台执行测试,然后在前端任务列表中查看对应的测试结果。这一过程大致经历 8 个过程:
1、被测文件上传
2、将文件路径传递给后端 python
3、python 根据路径和参数执行测试
4、python 保存测试结果到数据库 (如: rethinkdb)
5、前端发起查看测试报告的请求
6、Node.js 从数据库中获取测试结果
7、Node.js 将测试结果传递给前端
8、前端展示测试结果
我会逐一和大家介绍每一过程的具体实现:
文件上传
先上效果图:
定义一个 input 输入框,我使用了第三方库 dropzone 实现拖拽,通过添加 action 来定义文件上传后要执行的动作,代码如下:
input#dropfile.dropzone(action='/file_upload', name='filename', readonly='readonly', placeholder='将电脑里的文件拖拽到此上传,小于100M的APK文件')
在 app.js 中处理 file_upload 的 post 请求,代码如下:
/* 处理文件上传和保存 */
app.post('/file_upload', function (req, res) {
log.info('文件上传:' + req.files);
upload_file.save_app(req, res);
});
读取前端传递过来的文件,然后写到指定目录 uploads 下,代码如下:
exports.save_app = function(req, res){
var des_file = path.join(__dirname, '../../uploads', req.files[0].originalname);
fs.readFile(req.files[0].path, function(err, data){
fs.writeFile(des_file, data, function(err){
if(err){
var response = {
errcode:50004,
errmsg: err
};
log.info( response );
res.send(JSON.stringify(response));
}else{
var response = {
errcode:0,
filename:req.files[0].originalname
};
log.info( response );
res.send(JSON.stringify(response));
}
});
});
};
这样就完成了文件的上传。
创建一个任务,除了提交上传文件 (被测 app),可能还有其他参数,我们将所有参数写到表单 form 中。
form#Step-Two-Div.Step-two(role='form', action='/upload/success', method='post')
//提交任务的按钮类型为submit,此处还定义了一个变量type,值为:compatibility
button.Blue-button(type='submit', name='type', value='compatibility ')
| 提交任务
说明:提交任务时,会执行表单中的 action,即发起 /upload/success 请求,这里定义一个变量 type 是为了区分测试类型 (如兼容性、稳定性),不同的任务都提交到/upload/success, Node.js 端处理 upload/succes 的请求时通过判断 type 来区分测试类型,以便后端根据测试类型执行不同的 python 脚本。
在 app.js 中处理/upload/succes 的 post 请求,代码如下:
/* 处理提交参数 */
app.post('/upload/success', function (req, res) {
log.info(req.body);
var args = '';
var type = '';
if (req.body.filename === '' || req.body.filename === undefined) {
var response = {
errcode: 50001,
errmsg: '请上传文件'
};
log.info(response);
res.send(JSON.stringify(response));
return;
}
if (req.body.email === '') {
var response = {
errcode: 50002,
errmsg: '请填写邮箱地址'
};
log.info(response);
res.send(JSON.stringify(response));
return;
} else {
args += ' --email=' + req.body.email;
}
if (req.body.type !== undefined) {
type = req.body.type;
args += ' --test-type=' + type;
}
if (req.body.dev !== undefined) {
args += ' --dev=' + req.body.dev;
}
if (req.body.monkey !== undefined) {
args += ' --monkey=' + req.body.monkey;
}
apppath = path.join(__dirname, 'uploads', req.body.filename);
fs.exists(apppath, function (exists) {
if (!exists) {
var response = {
errcode: 50003,
errmsg: apppath + ' 文件不存在'
};
log.info(response);
res.send(JSON.stringify(response));
return;
} else {
args += ' --app-path=' + apppath;
log.info('args = ' + args);
if (type == 'feedback' || type == 'versiontest'){
args = apppath; // 数据分析模块只需要传递文件路径参数即可
child_services.startAnalysis(type, args);
}
else {
cmdqueue.inqueue(args);
}
rdb.findAll(function (tasks) {
res.render('testmanager', {
"task_list": tasks
})
});
}
});
});
在这个方法里面,获取前端传递过来的文件路径 req.body.filename、邮箱 req.body.email、测试类型 req.body.type,同时将这些参数放在 args 中,我们将 args 作为参数传递给 child_process,child_process 在调用 python 脚本时,将 args 传递给 python。child_process 中调用 python 脚本的代码如下:
var cmd = 'python devices.py' + args;
log.info('当前任务为:%s', cmd);
var child = child_process.exec(cmd, options);
cmd 范例如下:
python vendor/comptest/devices.py --app-path=/home/K米4.6.6.apk --email=xiongjinfei@star-net.cn --test-type=compatibility
今天就暂时先写到这里,后续章节会持续更新,敬请期待……