sptt规范介绍

时间:2022-05-05 08:11:54

相关资源

如何开发sptt工程的原子操作

移动端测试方案--sptt

sptt规范

一个标准的sptt工程的目录如下:

[sptt-project]
  | -- [ios]
  |      | -- [atoms]
  |      |      | -- login.yml
  |      |      | -- action.yml
  |      | -- [steps]
  |      |      | -- login.yml
  |      |      | -- buy.yml
  |      | -- [testcases]
  |      |      | -- firstcase.yml
  |      | -- caps.json
  | -- [android]
  |      | -- [atoms]
  |      |      | -- login.yml
  |      |      | -- action.yml
  |      | -- [steps]
  |      |      | -- login.yml
  |      |      | -- buy.yml
  |      | -- [testcases]
  |      |      | -- firstcase.yml
  |      | -- caps.json

sptt规定,测试用例的最小粒度为atom,即定义在atoms文件夹中的操作。多个atom操作按顺序可确定一个step,多个step操作组成一个测试用例。

atom操作

sptt将测试领域的测试用例分解为最基本的原子操作,即atom。按照人机交互过程,每个atom操作包含以下元素:

  • UI元素定位
  • UI元素操作
  • UI元素操作所需数据
  • 断言
  • 额外action

下面,将会详细这些元素

元素定位

sptt提供了几种元素定位方式:

  • id定位
    通过在yml文件中配置ui_id属性实现定位:

      start notification alert:
    ui_id: Allow
    ui_action: click

    如上例中的名为“start notification alert”的atom操作,采用了id定位方式。

  • name定位
    在yml中配置ui_name属性实现:

    login:
    ui_name: 登录
    ui_action: click

    上例中“login”的atom采用name定位方式选择登录按钮。

  • className定位
    在yml中配置ui_className属性实现,由于className的特殊性,一个className往往对应多个元素,因此在使用className定位元素时,需要配合管道符设定具体的元素索引值,索引值的范围为 [0, length-1]

      enter an hot sale's information:
    ui_className: Button|1
    ui_action: click

    上例中名为“enter an hot sale's information”的atom操作中,选择className为Button的元素数组,并返回数组中的第二项Button元素。

className定位方式,必须使用管道符号|来通过索引定位具体的元素,否则会出现异常。

  • xpath定位
    通常使用xpath定位xml文档元素,在appium中可能无法采用上述提供的几种定位方式,但是xpath却肯定可以,因为appium将试图解析为一颗xml对象树,只要提供正确合理的xpath,理应总能找到对应元素。不过,由于遍历xml树的复杂度相对较高,appium服务端采用xpath方式定位效率很低,因此不在极端情况下尽量不要使用xpath定位方式。

      get orderId:
    ui_xpath: //XCUIElementTypeApplication[1]/XCUIElementTypeWindow[1]/XCUIElementTypeOther[1]/XCUIElementTypeOther[1]/XCUIElementTypeOther[1]/XCUIElementTypeOther[1]/XCUIElementTypeOther[1]/XCUIElementTypeOther[1]/XCUIElementTypeOther[1]/XCUIElementTypeOther[1]/XCUIElementTypeOther[1]/XCUIElementTypeTable[1]/XCUIElementTypeCell[4]/XCUIElementTypeStaticText[5]
    ui_action: getValue

    上例采用了相对的xpath方式定位label元素,获取订单号。经测试性能很差。

  • accessibilityId定位
    accessibilityId是iOS开发中对象的一个属性,它给元素提供了一个可唯一标示的标识符,利用accessibilityId属性可以实现类似id定位的功能,在iOS开发中非常好用。

     return homepage:
    ui_accessibilityId: 回到首页
    ui_action: click
  • css定位
    css定位针对的是html5页面元素,在app中肯定有许多嵌入的html5页面,针对这些页面中的元素必须通过css进行定位,其中选择器的类型与js中“document.querySelector(selector)”相同。

      选择开店礼包:
    ui_css: .j_GiftItem:nth-child(2)
    ui_action: click
    sleep: 1000
      输入短信码:
    ui_css: .field>.checkcode>.checkcode-left>input
    ui_action: captcha
    data:
      tel: 15168253213
    sleep: 2000
    元素操作

    sptt提供了7种元素操作,分别为

  • click 点击
  • clickWithCoordinate 点击坐标所在元素
  • getValue 获取文本值
  • type 输入
  • doubleClick 双击
  • swipe 滑动
  • hideKeybord 隐藏键盘
  • captcha 获取手机验证码操作
  • removeApp 删除app
  • installApp 安装app

对应在atom文件中配置ui_action属性。

不过,clickWithCoordinate、type和swipe操作需要提供所需数据。

点击坐标

 enter order management:
    ui_action: clickWithCoordinate
    data:
      x: 20
      y: 300

clickWithCoordinate需要提供点击坐标的位置,可以不提供选择器(点击的坐标是绝对坐标,因此无需提供对应操作的元素);坐标信息可以通过app-inspector的bounds属性获得--bounds:10,30,72,29 意味坐标位置为(10,30),同时该元素的长度为72px,宽度为29px

输入框输入数据

input username:
    ui_xpath: //XCUIElementTypeOther/XCUIElementTypeTextField[1]
    ui_action: type
    data: showjohstp

type的数据为需要向输入框输入的源数据,“input username”atom操作向对应xpath的元素输入内容“showjohstp”;

滑动

swipe则需提供滑动的相对视口(可理解为屏幕的长度和宽度)百分数和滑动时长。

  swipe down:
    ui_action: swipe
    data:
      sxRatio: 0.5
      syRatio: 0.8
      exRatio: 0.5
      eyRatio: 0.1
      duration: 400

“swipe down”操作则在0.4s内从起点坐标(0.5 * width,0.8 * height)滑动到(0.5 * width,0.1 * width)处,即向下滑动。sxRatio和exRatio指定相对视口宽度的相对值;syRatio和eyRatio指定相对视口高度的相对值。

验证码操作

在做自动化时会遇到手机验证短信的情况,在sptt中采用一种hack方式:查询对应redis服务器获取验证码,因此性能比实际的短信获取更好,且安全性更高。

获取验证码操作需要提供手机号码(data中的tel数据)和需要填写的输入框(ui_css):

 input captcha:
    ui_css: .field>.checkcode>.checkcode-left>input
    ui_action: captcha
    data:
      tel: 15168253213
    sleep: 2000

删除app

如果需要删除某个app,需要使用该操作:

  remove app:
    ui_action: removeApp
    data: com.showjoy.shop

其中,data提供该app的包名,如达人店的“com.showjoy.shop”

安装app

同理,安装app需要提供url:

install app:
    ui_action: installApp
    data: https://wireless-build.showjoy.net/job/ShopAndroid-develop/283/artifact/outputs/apk/shopandroid-2.0.1.1-forTest-20170413104803.apk
数据

有些“ui_action”需要提供数据,如“type”操作。在上节中的某些实例中也有呈现,data可以是字符串,也可以设置为对象的形式,如:

enter order management:
    ui_action: clickWithCoordinate
    data:
      x: 20
      y: 300

上例中的data其实就是类似{x: 20,y: 300}的对象。

动态生成数据

sptt提供了data的编程能力,可以在data中执行JavaScript表达式,执行结果作为data的值。其中,表达式需要放在<% %>占位符内部,如下例:

输入店铺名称:
    ui_xpath: //android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.RelativeLayout[1]/android.widget.LinearLayout[1]/android.widget.LinearLayout[2]/android.widget.RelativeLayout[3]/android.widget.RelativeLayout[1]/android.widget.LinearLayout[1]/android.widget.EditText[1]
    ui_action: type
    # <%%>内部执行JavaScript表达式
    data: <%String(Date.now()).slice(0,10)%>

此处填写店铺名称,由于店铺名称的唯一性(不可重复),因此在此处生成一个10位的时间戳作为店铺名称。

断言和断言类型

测试离不开断言,UI自动化测试的断言比较简单,目前sptt仅仅是根据当前视图中是否存在另一个元素来判断atom操作是否成功。因为多数UI操作都会直接影响视图,所以这种断言方式可满足大多数操作。而针对不会影响视图的UI操作,sptt并未做断言处理,理论上来说也不需做处理,必应从产品角度上说每一次UI操作都会在视图层提醒用户状态的切换。

sptt规范目前提供了几种与断言相关的元素定位方式:

expectation_id
expectation_name
expectation_className
expectation_xpath
expectation_css(html5中的元素)

同时提供多种断言方式“expectation_type”:

expectation_type: none
expectation_type: exist
expectation_type: contain

针对expectation_type: contain方式,用来判断UI元素的内容是否包含给定为本,因此需要expectation_data属性进行搭配:

expectation_data: 家族纳新奖励收益

如下面的例子

  进入收益明细页面:
    ui_xpath: //android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.RelativeLayout[1]/android.widget.ScrollView[1]/android.widget.RelativeLayout[1]/android.widget.RelativeLayout[1]/android.widget.LinearLayout[1]
    ui_action: click
    sleep: 10000
    expectation_css: .income-detail-item:nth-child(1) .comm-info #获取文本"家族纳新收益。。。"
    expectation_type: contain
    expectation_data: 家族纳新奖励收益

点击xpath对应的元素,等待10s后,判断html5页面中选择器为“.income-detail-item:nth-child(1) .comm-info”的DOM元素的文本值是否包含给定的文本--“家族纳新奖励收益”,不包含则断言失败。

这里的“contain”是指包括,是给定文本的父集。

find info of good 1:
  ui_name: 商品详情
  ui_action: click
  sleep: 100
  expectation_id: 回到主页
  expectation_type: exist

在“find info of good 1”atom,点击“商品详情”按钮,等待100ms后,如果当前视图中存在id为“回到主页”的元素,那么我们就认为断言成功,即当前atom操作执行成功。

find info of good 2:
  ui_name: 商品详情
  ui_action: click
  sleep: 100
  expectation_name: 回到主页
  expectation_type: none

相反的,如果点击“商品详情”按钮,等待100ms后,视图中不存在name为“回到主页”的元素,则认为断言成功。

额外操作
  • sleep
    由于UI自动化测试是将人为性的操作转接为模拟器自行测试,无法做到像人那般灵活,因此为了尽量减少应用中视图切换延时造成的问题,sptt给atom操作添加了sleep操作。测试人员可以设定atom操作后sleep的时间,来确保下一个试图状态是我们所期待的。

在达人店iOS测试版本中,订单管理页面有两个tab栏:本店订单和个人订单。我们需要获取自己刚下的订单号,但是默认进入的本店订单tab页,同时加载数据,显示加载gif动态图。此时,我们通过yml配置响应流程,在订单管理页面直接进入个人订单tab页,会出现错误,无法正常进入。原来,这是由于在默认进入的本店订单页面,会像服务端加载订单数据,同时整个视口都会显示gif动态图,这样点击个人订单按钮就会失败,无法进入。 这种情况下,就需要使用sleep操作:在进入订单管理页面时,设置sleep 5000,待数据加载并渲染完成后再进行点击个人订单按钮。

  • 网络请求
    sptt默认提供了网络请求模块,使用者可以提供相关链接及头信息即可完成请求。网络模块提供了3个参数,分别为url,qs和headers,其中url为请求链接,qs为查询字符串,headers则为请求头部。

     fake pay:
    ui_action: net
    data:
      url: http://shopappserver.showjoy.net/Fake_Pay
      qs:
        orderNumber: ${idid}
        identify: ${x_request}
      headers:
        cookie: ${ticket}

    示例代码中,ui_action为net,并设置data属性为一个包含“url、qs和headers”的对象。上例中data配置项中存在3个变量,分别为“idid,x_request和ticket”,分别对应“订单号、请求标示和登录信息”,这样携带以上信息的请求可以正常访问,实现伪支付的功能。

net请求可以不使用变量,但是如果像上例中使用变量的情况下需要在step操作中提供对应的变量值,请看下例中的step操作

fake pay the order:
    - ActionAtoms | backward
    - ActionAtoms | fake pay:
        params:
          idid: ActionAtoms | get orderId
          x_request: 11232123
          ticket: tgc=bsK6KS0wQi;um_remember="5385980EA93F8265018C9FCD285B8ED7:2E175E4D7F73DDD96CC2524B965E12A6:CC1F08AA5F8A0FA68B8D3532EA3C68AC";

在名为“fake pay the order”的step操作中,包含了两个atom操作,其中第二个“fake pay”操作为前文例子中定义的atom操作。通过在此处配置params属性设置对应的变量值:

idid: ActionAtoms | get orderId: 变量idid的值为get orderId操作的返回值(get orderId是一个getValue类型的atom操作,它会返回订单号)

x_request: 11232123: 设置x_request的值为一个常量

ticket: tgc=bsK6KS0wQi;um_remember="5385980EA93F8265018C9FCD285B8ED7:2E175E4D7F73DDD96CC2524B965E12A6:CC1F08AA5F8A0FA68B8D3532EA3C68AC";:设置ticket值为一串登录信息,这段字符串包含了服务端认证用户的两个必须的cookie

sptt向使用者提供了可配置的接口文件,实现了网络请求。

step操作

上节中详细介绍了atom操作的组成,了解到atom是sptt规范中的最小粒度,而step操作则是由若干个atom操作组成的,实现有限功能的atom集合。这里提到的有限功能是指,“实现部分流程化的可复用的部分”。

举一个例子,在“下订单”这个测试用例中,需要首先进行“用户登录”,再进入相关商品界面进行购买,下订单。那么,可以把“登录”流程封装为一个step操作,它实现了部分功能(登录),同时也可为其他测试用例复用,这就是一个规范的step划分。

在具体书写step操作时,每一个yml文件是一个steps集合,该集合中存放相关的step操作:

---
BuySteps:
  enter my shop and buy sth:
    - TestUIAtoms | enter my tab
    - TestUIAtoms | enter test entry
    - TestUIAtoms | enter my shop
    - TestUIAtoms | enter an hot sale's information
    - TestUIAtoms | buy now
    - TestUIAtoms | submit order

  fake pay the order:
    - ActionAtoms | backward
    - ActionAtoms | close webview
    - ActionAtoms | return homepage
    - TestUIAtoms | enter my tab
    - TestUIAtoms | enter test entry
    - TestUIAtoms | order management
    - TestUIAtoms | my orders
    - ActionAtoms | fake pay:
        params:
          idid: ActionAtoms | get orderId
          x_request: 11232123
          ticket: tgc=bsK6KS0wQi;um_remember="5385980EA93F8265018C9FCD285B8ED7:2E175E4D7F73DDD96CC2524B965E12A6:CC1F08AA5F8A0FA68B8D3532EA3C68AC";

在BuySteps集合中,包含了两个step操作:“enter my shop and buy sth” 和 “fake pay the order”,每个step操作中,按顺序执行atom操作。

testcase操作

testcase操作即为测试领域的测试用例概念,一个testcase由若干个step有机组成。在编写yml时,我们是在配置testcases集合,每一组testcases集合共用相同的测试环境(系统、硬件和其他项)。

---
交易链路:
  config:
    timeout: 200000
    caps: ios/caps.json
  下订单流程:
    - LoginSteps | login
    - BuySteps | enter my shop and buy sth

  支付流程:
    - BuySteps | fake pay the order

在名为“交易链路”的套件(用例集)中,包含了两个测试用例,同时也有这个套件的相关配置项timeout: 200000;caps: ios/caps.json。 设置了这两个测试用例总共执行的时间不超过200s,否则报错默认执行失败;并提供环境变量的路径在ios/caps.json下。

caps配置

sptt工程的ios和android目录下都有一个“caps.json”配置文件,该文件定义了测试环境。

ios的caps.json配置

{
  "appium-version": "1.6.3",
  "platformName": "iOS",
  "platformVersion": "10.2",
  "deviceName": "iPhone 7",
  "autoAcceptAlerts": true,
  "automationName": "xcuitest",
  "newCommandTimeout": 3600,
  "noReset": true,
  "app": "http://shop.showjoy.net/autotest/ios/0.0.3/DaRenShop.zip"
}

这里我们需要关心的主要是“platformName”、“platformVersion”、“deviceName”和“app”。

前三个对应于系统、版本号和硬件。“app”则为需要测试的包,ios下后缀名为“.app”,android下为“.apk”,在这里我们引用线上的测试包进行测试。测试包的发布,请看文章 sptt命令详解

android的caps.json配置

{
  "appium-version": "1.6.3",
  "platformName": "Android",
  "deviceName": "darendian",
  "app": "/Users/showjoy/github/telentshop/shopandroid/build/outputs/apk/shopandroid-debug.apk",
  "noReset": true,
  "appPackage": "com.showjoy.shop",
  "appActivity": "com.showjoy.shop.module.splash.SplashActivity",
  "appWaitActivity": "com.showjoy.shop.module.login.LoginActivity"
}

android的配置与ios的配置大同小异,区别在于android下需要提供deviceName、appPackage、appActivity和appWaitActivity属性。

“deviceName” 在android下无须像ios那样指定设备类型,但是必须提供一串字符用以标明设备名称,不能为空

“appPackage”为Android应用的包名;

“appActivity”为应用包中启动的 Android Activity 名称;

“appWaitActivity”为要等待启动的 Android Activity 名称。

android的打包事项

在gradle文件中,需要针对代码设置打包配置,此处需要设置debuggable、minifyEnabled、zipAlignEnabled等选项,在实际实践中发现,一旦debuggable设置为false,则无法进入webview上下文,因此此处需要特别注意。

android下的weex页面

android下的weex页面可以正常定位,不过如果要获取UI的文本值则需要获取view的“content-desc”属性,而通过sptt定位的元素没有该属性,通过阅读appium源码可发现“content-desc”对应的元素的“name”属性,因此在sptt内部通过“name”属性获取weex中的文本值。