TA的每日心情 | 奋斗 2021-8-6 16:14 |
---|
签到天数: 1 天 连续签到: 1 天 [LV.1]测试小兵
|
不太会写,就简单直接的描述一下!希望对初学者上手会有些帮助;
其中还有许多需要完善和补充后面会陆续进行改进提交, 希望有同学能参与 补充完善!
首先需要感谢,macaca 项目组的各位大神 提供的这一系列的 测试工具; 感谢!
模型简介:
1.可以录制;
2.可以回放;
3.可以固化用例,多层分离管理!
简单操作方式如下:
录制:
uirecorder start --mobile sample/test.IOS3.js
回放:
source run.sh sample/test.IOS3.js
执行固化用例:
source run.sh testsuite/test.B2C.3.0.4.js
固化用例采用4层分离模式:
第一层: 页面元素数据层;
第二层:页面操作层;
第三层:用例层,或耦合关键字层;
第四层:suite层,业务场景层;
核心:
通用方法js模块;
commons.js
接入手机自动识别、app启动、用例执行、用例截图 等方法,这个是从录制脚本中抽离出来的,只多加了 reuse
参数 可以配置要不要预装app;
commBrowser.js
浏览器或手机操作方法;
commElem.js
被测元素对象公共操作方法;
commShould.js
公共断言方法;
分层结构如下图:
- 第一层:元素数据层
- 存放,元素对象的 xpath id 等;
- 如:
- exports.btnLoginPar = {
- androidElem: '//*[@resource-id="com.ndol.sale.starter:id/btn_login"]',
- iosElem: '//*[@name="登录/注册"]',
- elementDesc: '登录/注册',
- waitTime: 30000
- };
- // 商品分类 ,商品列表中 商品的 名称
- exports.goodsNamePar = {
- androidElem: '//*[@resource-id="com.ndol.sale.starter:id/projuctTitle"]',
- elementDesc: '商品名称'
- };
- 第二层:页面操作层
- 存放,对页面元素的操作方法;
- 如:
- exports.swipeGoodsName = function (type, index){commElem.waitElemAndSwipe(goodsPageUI.goodsNamePar, type, index, 5);};
- exports.swipeGoodsNameLastToFrist = function (){
- commElem.waitElemAndSwipeLastToFrist(goodsPageUI.goodsNamePar);
- };
- 第三层:用例层,或耦合关键字层
- 如:
- exports.goodsListSwipeTest = function(){
- //适用版本 3.0.0--3.0.4
- commBrowser.testCaseDoc("验证商品列表 向上滑动,隐藏 列表上方 tab 和 下方 tab ");
- unitPage.clickGoods();
- goodsPage.clickCategoryXXSP();
- // goodsPage.getGoodsNameSize(); //打印出 元素对象 的坐标信息
- goodsPage.swipeGoodsName('up', 1); //将第2个商品向上滑动
- // commBrowser.swipeOnce(600,1000,600,400); //滑屏
- commShould.elemCanNotFind('全部'); // 全部 等 上方 tab 被隐藏
- commShould.elemCanNotFind('分类'); // 分类 等 下方 tab 被隐藏
- goodsPage.swipeGoodsName('down', 1); //将第2个商品向下滑动
- commShould.elemCanFind('全部'); // 全部 等 上方 tab 显示
- commShould.elemCanFind('分类'); // 分类 等 下方 tab 显示
- };
- exports.loginTest = function(){
- //适用版本 3.0.0--3.0.4
- commBrowser.testCaseDoc("登录流程 ");
- unitPage.clickMine(); //点击 “我的”
- minePage.clickBtnLogin(); //点击注册登录
- minePage.login(userName, password);
- minePage.clickIvAvatar(); //点击 “我的资料”
- unitPage.clickArrowBack(); //返回 我的
- };
- 第四层:suite层,业务场景层
- 启动被测app,运行测试前准备,执行用例 等;
- var commons = require('../commons/commons');
- var rootPath = commons.rootPath;
- var appPath = rootPath + '/app/b2c_v3.0.4_112.apk';
- function testcase(){
- var b2c_mine = require('../testcase/mineTest');
- var b2c_goods = require('../testcase/goodsTest');
- var b2c_order = require('../testcase/orderTest');
- var b2c_home = require('../testcase/homeTest');
- // app安装完成,开始执行用例***************************
- b2c_home.unloginDismissCouponTest();
- b2c_home.unloginStatusToLoginTest();
- b2c_order.unloginStatusToLoginTest();
- b2c_mine.unloginStatusToLoginTest();
- b2c_mine.userSettingTest();
- b2c_goods.goodsListSwipeTest();
- b2c_goods.findGoodsByName();
- b2c_goods.addCartTest();
- b2c_goods.addCartTest2();
- // ************登录后用例****************************
- b2c_mine.loginTest();
- b2c_mine.getUserInfo();
- b2c_mine.loginStatusToLoginTest();
- b2c_order.allOrderListTest();
- // // ************退出登录****************************
- b2c_mine.loginOffTest();
- // 用例执行结束**************************************
- }
- if(module.parent && /mocha\.js/.test(module.parent.id)){
- commons.runThisSpec(appPath, testcase);
- }
- function callSpec(name){
- try{
- require(rootPath + '/' + name)();
- }
- catch(e){
- console.log(e)
- process.exit(1);
- }
- }
- 通用操作方法
- 如:
- /*
- *等待 对象的出现 ,向指定 方向 拖拽
- * @param androidElem 安卓对应的元素对象的获取方式 及 值
- * @param iosElem ios对应的元素对象的获取方式 及 值
- * @param elementDesc 控件描述文案
- * @param waitTime 等待元素对象刷新的 等待时间
- * @param type 滑动的方向 'up'、down'、'right'、'left'
- * @param index 元素的位标 从 0 开始
- * @param times 移动距离(宽或高)的倍数,默认1
- */
- exports.waitElemAndSwipe = function (parameter,type,index,times){
- var androidElem = parameter.androidElem;
- var iosElem = parameter.iosElem?parameter.iosElem:parameter.androidElem; //如果没有传ios的默认使用Android的
- var elementDesc = parameter.elementDesc;
- var waitTime = parameter.waitTime?parameter.waitTime:5000;
- var index = index || 0;
- var times = times || 1;
- var type = type || 'up';
- it('拖拽: 将第 ' + index + ' 个 ' + elementDesc + ' 元素,向' + type + '拖拽' + times + '个自身高度或宽度', function (){
- if(platformName === 'Android'){
- return driver.wait(androidElem, waitTime).get(index)
- .rect()
- .then(_get_element_rect)
- .then(function(par){
- // console.log(par);
- return _swipeElemByType(par, type, times);
- });
- }else{
- return driver.wait(iosElem, waitTime).get(index)
- .rect()
- .then(_get_element_rect)
- .then(function(par){
- // console.log(par);
- return _swipeElemByType(par, type, times);
- });
- };
- });
- };
- /*
- * 在当前页面 对 textAffirm 进行 未显示 断言
- * @param androidElem 安卓对应的元素对象的获取方式 及 值
- * @param iosElem ios对应的元素对象的获取方式 及 值
- * @param elementDesc 控件描述文案
- * @param waitTime 等待元素对象刷新的 等待时间
- * @param textAffirm 断言
- */
- exports.elemCanNotFind = function (textAffirm){
- it('不存在断言:当前页面不存在文本元素对象 "' + textAffirm + '"', function (){
- if(platformName === 'Android'){
- return driver.find('//*[@text="' + textAffirm + '"]')
- .should.is.empty; //判断当前页面没有找到该元素对象
- }else{
- return driver.find('//*[@name="' + textAffirm + '"]')
- .should.is.empty;
- };
- });
- };
复制代码
在后边说一些题外话!可以忽略!
开始使用 uiRecorder 录制,是为了 方便学习,后来发现录制完之后,用例显得特别臃肿庞大,
而且大量冗余,不方便工程化,就试着将录制的脚本进行固化、工程化,然后慢慢的就有了下面这些东西;
使用过程中 发现 对 IOS的录制和回放 相对 Android 要慢太多,希望各位大神 持续改进,好跟着喝汤!
所以模型中的东西,虽然是针对Android 和 IOS做方法统一,但实际上大部分只能Android跑通;
当然 我 用这一套的目的,也并不是要用来做 严谨的 业务逻辑UI自动化验证(这一块主要通过接口自动化实
现,已大量覆盖),
主要的目的是做一些:
日常 功能及功能页面巡检(每天定时跑个几次);
兼容性,就是接上不同的机型 各跑几次;
验证 一些 前端处理的简单逻辑 ;
等等
|
|