构建行为驱动的iOS自动化测试

本文介绍了如何用行业流行的行为驱动BDD框架Cucumber作为测试框架,使用Node.js 编程语言结合Appium开发iOS原生应用的自动化测试。本文使用了BDD的可视化开发工具CukeTest (cuketest.com)

主要内容

  • 准备被测应用app

  • 编写用例的场景描述

  • 安装自动化库

  • 生成、完善测试代码

  • 运行

  • 生成测试报告

前提条件

  • 准备一台Mac电脑

  • 配置appium 具体可参考 appium.io/docs/cn/app…

  • 安装CukeTest,自动化脚本开发工具,下载地址: cuketest.com/download

下载时请选择Mac版

1. 准备被测试的应用app

本次教程使用https://developer.apple.com官网提供的教学的样例作为被测app,iOS app制作过程可以参考官网教程 developer.apple.com/library/arc…

应用源码 developer.apple.com/sample-code…

源码下载后解压,使用xcode打开源码。执行编译,app UI界面如下

2. 编写用例的场景描述

行为驱动(BDD)的优势就是可以用自然语言描述测试场景,并与代码相关联,提高了可读性和可维护性。它从被测应用的外部描述应用的行为,再转换为自动化脚本,让自动化测试的开发变得非常有条理。

我们这里就按照行为驱动的最佳实践,先编写中文的场景描述。步骤如下:

a. 首先打开CukeTest,新建项目,项目模板选择--基本模版,点击创建。

b. 项目创建成功后默认项目结构为:

c. 在feature文件中编辑测试用例:可以手动在可视化界面编写用例,也可以在文本界面编写用例。



# language: zh-CN
功能: IosDemo 操作
常见的增删改查操作

  场景: 添加一个新的记录
    假如点击添加按钮
    当meal name 中输入"abcdefg"
    同时点击图片从相册中选择一张图片
    并且选择4颗星
    当点击保存按钮
    那么首页应该会有4个列表

  场景: 修改一条记录
    假如选择点击最后一个列表
    当文本输入框中的更改值为"HelloWorld"
    同时点击保存按钮
    那么首页最后一个列表文本值应该为"HelloWorld"

  场景: 删除一条记录
    假如点击Edit按钮转换为可编辑状态
    当选择最后一个列表
    同时点击删除
    那么此列表应该被删掉

复制代码

对应的可视化界面为:

有了场景描述,下面就是实现这个场景的自动化。

  1. 安装自动化库
  • 安装wd.js

    appium支持的JavaScript库有wd.js, webdrerio.js 本次使用wd.js 库作为appium的客户端实现,关于appium的API,更多请参考:appium.io/docs/en/abo…

  • 安装方式

    在项目的根目录下,执行npm install wd --save

    (备注:可以在CukeTest 文件导航栏项目名称处 右键--在命令行窗口中显示, 导航到项目的根目录下)

4. 生成自动化脚本

CukeTest 提供了将测试用例描述转化为自动化代码的功能,在CukeTest 中打开 step_definitions/definitions1.js 文件,点击测试用例后的灰色按钮即可在definatons1.js文件中自动生成框架代码:

然后只要在框架代码中填充实现就可以了。

5. 完善自动化代码

features目录下新建get_driver.js,定义驱动生成。

let wd = require('wd')function createDriver(){
    return wd.promiseChainRemote({
        host: '127.0.0.1',
        port: 4723
    });}

exports.driver = createDriver()
复制代码

在features目录下创建 support.js. 设置运行时

let {BeforeAll,Before,After,AfterAll,setDefaultTimeout} = require('cucumber')
let path = require('path')
let cuketest = require('cuketest');
let {driver} = require('./get_driver')

// 设置超时时间为60秒
setDefaultTimeout(60*1000)

// 所有用例执行前
BeforeAll(async function(){
    await cuketest.minimize()
    // 模拟器设置
    let desiredCaps = {
        platformName: "iOS",
        platformVersion: "11.4",
        deviceName: "iPhone 7",
        automationName: "XCUITest",
        app: path.resolve('/Users/zack/Library/Developer/Xcode/DerivedData/FoodTracker-bidmzqqybmbcqcbncwomyqmqbvoi/Build/Products/Debug-iphonesimulator/FoodTracker.app')//ios app文件路径
    };


    await driver.init(desiredCaps);
    await driver.setImplicitWaitTimeout(15000);
    
})

//每个场景执行后截图
After(async function(){
    let screenshot = await driver.takeScreenshot();
    this.attach(screenshot, 'image/png');
    
})

//所有场景执行完的操作
AfterAll(async function(){
    await cuketest.restore();
    return driver.quit();
        
})

复制代码

完善definitions1.js 文件,根据定义的测试用例,实现相关的操作方法。


const { Given, When, Then } = require('cucumber');

let { driver } = require('../support');

let assert = require('assert');

 你的步骤定义 /

Given(/^点击添加按钮$/, async function () {
    await driver.elementByAccessibilityId("Add").click();
    
});

When(/^meal name 中输入"([^"]*)"$/, async function (text) {

    let edit = await driver.elementByIosClassChain('**/XCUIElementTypeTextField[`value == "Enter meal name"`]')
    await edit.click();
    await edit.sendKeys(text);});When(/^点击图片从相册中选择一张图片$/, async function () {

    let uploadImage = await driver.elementByAccessibilityId('defaultPhoto')
    await uploadImage.click();


    let Moments = await driver.elementByAccessibilityId('Moments')
    await Moments.click();


    let allimge = await driver.elementsByIosClassChain('**/XCUIElementTypeCollectionView/**/XCUIElementTypeCell')

    console.log("length is ",allimge.length);

    let index = Math.floor(Math.random() * Math.floor(allimge.length))
    await allimge[3].click();
        
    });

When(/^选择(\d+)颗星$/, async function (arg1) {

    await driver.elementByAccessibilityId('Set 4 star rating').click();
    
});
    
When(/^点击保存按钮$/, async function () {

    await driver.elementByAccessibilityId('Save').click()
        
    
    
});

Then(/^首页应该会有(\d+)个列表$/, async function (num) {

    let itemlist = await driver.elementsByIosClassChain('**/XCUIElementTypeTable/**/XCUIElementTypeCell')
    return assert.equal(num,itemlist.length)
    
});

Given(/^选择点击最后一个列表$/, async function () {

    let itemlist = await driver.elementsByIosClassChain('**/XCUIElementTypeTable/**/XCUIElementTypeCell')
    await itemlist[itemlist.length - 1].click()});

When(/^文本输入框中的更改值为"([^"]*)"$/, async function (text) {

    let edit = await driver.elementByIosClassChain('**/XCUIElementTypeTextField')
    await edit.click();
    await edit.clear();
    await edit.sendKeys(text);
    await driver.hideDeviceKeyboard();});

Then(/^首页最后一个列表文本值应该为"([^"]*)"$/, async function (textval) {

    let itemlist = await driver.elementsByIosClassChain('**/XCUIElementTypeTable/**/XCUIElementTypeCell')

    let last = itemlist.length - 1;
    let element = itemlist[last].elementByIosClassChain('**/XCUIElementTypeStaticText')
    let text = await element.text();
    return assert.equal(text,textval);
    
});

Given(/^点击Edit按钮转换为可编辑状态$/, async function () {

    await driver.elementByAccessibilityId('Edit').click();
    
});

When(/^选择最后一个列表$/, async function () {

    let itemlist = await driver.elementsByIosClassChain('**/XCUIElementTypeTable/**/XCUIElementTypeCell')

    let last = itemlist.length - 1;
    let del = await itemlist[last].elementByXPath('//XCUIElementTypeButton[5]')
    await del.click();
    
});

When(/^点击删除$/, async function () {

    await driver.elementByXPath('(//XCUIElementTypeButton[@name="Delete"])[1]').click();});Then(/^此列表应该被删掉$/, async function () {
    let itemlist = await driver.elementsByIosClassChain('**/XCUIElementTypeTable/**/XCUIElementTypeCell')
    
    return assert.ok(itemlist.length == 3)
    
        
    });

复制代码

此时,feature文件后面的操作步骤后面会变成绿色,表示此步骤有代码实现。

点击绿色按钮,可以跳转到代码实现部分,这样对于修改代码也非常方便。

6. 运行

自动化代码编辑完后,命令行中 启动appium,直接运行appium 即可。

$ > appium
[Appium] Welcome to Appium v1.8.1[Appium] Appium REST http interface listener started on 0.0.0.0:4723
复制代码

CukeTest 中点击”运行“按钮或者点击”运行项目“按钮,即可运行自动化脚本。

7. 生成测试报告

点击”运行项目“按钮,自动化脚本运行完成后会自动生成测试报告,其中自动会包含每个场景运行完的截屏:


获取更多信息,可以关注公众号,也可以加QQ群:707467292 进行node.js自动化相关技术交流。

你可能感兴趣的:(测试,移动开发,xcode)