原文地址:自动化测试工具
Instrumenttation
UIAutomator +uiautomatorviewer
Selendroid
Robotism
Appium
selenium
单元测试
python的第三方库
一般进行接口测试时,每个接口的传参都不止一种情况,一般会考虑正向、逆向等多种组合,所以在测试一个接口时,通常会编写多条case,而这些除了传参不同外,并没有什么区别。这个时候就可以利用ddt来管理测试数据,提高代码复用率。
基本python语言的lettuce框架
什么是BDD
行为驱动开发是一种敏捷软件开发技术,它鼓励软件项目开发者、QA和非技术人员或商业参与者之间的协作。主要是从用户的需求出发,强调系统行为。BDD包括验收测试和客户测试驱动等的极限编程的实践,作为对测试驱动开发的回应。
Robot Framework是一款python编写的功能自动化测试框架。具备良好的可扩展性,支持关键字驱动,可以同时测试多种类型的客户端或者接口,可以进行分布式测试执行。主要用于轮次很多的验收测试和验收测试驱动开发(ATDD)。
测试报告管理(HTMLTestRunner)
邮件服务管理
postman
python requests
Load-runner
Jmeter
常规可输入的内容、数字、字符串、特殊字符、转义字符等。
非常规有一定含义的,html标签、css、javascript代码、url等
输入内容的边界、空字符、超长文本(边界值+1,-1)
根据产品的用户分布、手机品牌、分辨率、选择topN机型
根据产品在不同浏览器上的占有率,选择主要的浏览器测试
关注的问题,页面渲染、页面布局等,借助firebug调试
GPS(每秒查询率),Query Per Second,每秒钟能处理的请求数
从点击开始到页面完全加载,平均耗时情况
加载的页面大小,资源(JS,CSS文件)的数量等
JS注入
SQL注入
查询接口的正确性验证
查询接口对一些异常数据的容错情况
查询接口在非浏览器环境下的处理情况
保证线上服务的质量,建立实时监控
及时发现异常情况,降低对用户的影响
基于Selenium实现UI自动化
例行回归验证,提高效率
Android使用Appium基于UIAutomator,IOS使用WDA
# -*- coding: utf-8 -*-
# !/usr/bin/python3
# author by : yuxiangShi
# tell by: 18538187569
# Animal是类,相同事物的统称
class Animal(object):
def run(self):
print('Animal is running...')
# Dog类,继承于Animal
class Dog(Animal):
pass
puppy = Dog()
puppy.run()
# 多态,子类方法覆盖父类方法
class Cat(Animal):
def __init__(self, name):
# __name是属性
self.__name = name
def getName(self):
print(self.__name)
def run(self):
print('Cat is running....')
# limi是一个猫类的实例
limi = Cat("limi")
# run是实例的一个方法
limi.run()
# getName方法
limi.getName()
输出:
Animal is running...
Cat is running....
limi
# 进程
from multiprocessing import Process
def foo(i):
print("This is Process", i)
for i in range(5):
p = Process(target=foo, args=(i,))
p.start()
输出:
This is Process 0
This is Process 1
This is Process 2
This is Process 3
This is Process 4
# 线程
import threading
def show(i):
print('This is Thread', i)
for i in range(5):
t = threading.Thread(target=show, args=(i,))
t.start()
输出:
This is Thread 0
This is Thread 1
This is Thread 2
This is Thread 3
This is Thread 4
# 协程
import gevent
def foo():
print("start_foo")
gevent.sleep(2)
print("end_foo")
def bar():
print("start_bar")
gevent.sleep(0)
print("end_bar")
gevent.joinall({
gevent.spawn(foo),
gevent.spawn(bar),
})
# -*- coding: utf-8 -*-
# !/usr/bin/python3
# author by : yuxiangShi
# tell by: 18538187569
# 服务端
# 导入socket模块
import socket
# 创建socket对象
s = socket.socket()
# 绑定端口
s.bind(("127.0.0.1", 6666))
# 等待客户端连接
s.listen(5)
while True:
# 建立客户端连接
c, addr = s.accept()
print('连接地址:', addr)
c.send("Welcome")
# 关闭连接
c.close()
# -*- coding: utf-8 -*-
# !/usr/bin/python3
# author by : yuxiangShi
# tell by: 18538187569
# 导入模块
import socket
s = socket.socket()
s.connect(("127.0.0.1", 6666))
server_reply = s.recv(1024)
print(server_reply)
s.close()
# -*- coding: utf-8 -*-
# !/usr/bin/python3
# author by : yuxiangShi
# tell by: 18538187569
# 计算平方
def square(x):
return x ** 2
print(square(10))
# lambda表达式
r = lambda x: x ** 2
print(r(10))
输出:
100
100
# -*- coding: utf-8 -*-
# !/usr/bin/python3
# author by : yuxiangShi
# tell by: 18538187569
tuple_a = (1, 2, 3, 4, 5)
list_b = [1, 2, 3, 4, 5]
tuple_a[0] = 10
list_b[0] = 10
print(tuple_a)
print(list_b)
# -*- coding: utf-8 -*-
# !/usr/bin/python3
# author by : yuxiangShi
# tell by: 18538187569
# range生成从0到100的列表
alist = range(0, 100)
print(alist)
# 设置步长为2
blist = range(2, 101, 2)
print(blist)
# -*- coding: utf-8 -*-
# !/usr/bin/python3
# author by : yuxiangShi
# tell by: 18538187569
line = "I am super man!"
# string的split方法
print(line.split(" "))
# re的split方法
import re
print(re.split("[m]", line))
输出:
['I', 'am', 'super', 'man!']
['I a', ' super ', 'an!']
# -*- coding: utf-8 -*-
# !/usr/bin/python3
# author by : yuxiangShi
# tell by: 18538187569
# args
# def test_args(first, *args):
# print(first)
# for v in args:
# print("args %s" % v)
#
#
# test_args(1, 2, 3, 4, 5)
# kwargs
def test_kwargs(first, *args, **kwargs):
print(first)
for v in args:
print("args %s" % v)
for k, v in kwargs.items():
print("kwargs", (k, v))
test_kwargs(1, 2, 3, 4, 5, k0=4, k1=5, k2=6)
输出:
1
args 2
args 3
args 4
args 5
kwargs ('k0', 4)
kwargs ('k1', 5)
kwargs ('k2', 6)
# -*- coding: utf-8 -*-
# !/usr/bin/python3
# author by : yuxiangShi
# tell by: 18538187569
import re
s1 = "helloworld,helloworld"
w1 = "hello"
w2 = "world"
# search扫描整个字符串
print(re.search(w1, s1))
# print(re.search(w1, s1).group())
# match只在字符串开始位置匹配
print(re.match(w1, s1))
# print(re.match(w1, s1).group())
# -*- coding: utf-8 -*-
# !/usr/bin/python3
# author by : yuxiangShi
# tell by: 18538187569
# 写文件
f = open('test.txt', 'wt')
f.write("hello world")
f.close()
# 使用with,追加内容,不用关系文件关闭问题
with open("test.txt", 'at') as f:
f.write("\nhello mook")
# 读取文件
with open("test.txt", 'rt') as f:
print(f.read())
# -*- coding: utf-8 -*-
# !/usr/bin/python3
# author by : yuxiangShi
# tell by: 18538187569
from sys import getrefcount
# 引用计数
a1 = 1000000
a2 = 1000000
del a1
del a2
print(id(a1))
print(id(a2))
# 检验a1和a2是同一个东西
print(a1 is a2)
# 获取a2的引用计数
print(getrefcount(a1))
# -*- coding: utf-8 -*-
# !/usr/bin/python3
# author by : yuxiangShi
# tell by: 18538187569
test1 = {'key1': 2, 'key1': 3, 'key1': 4}
kv1 = test1.items()
# print(next(kv1))
kv2 = test1.iteritems()
print(next(kv2))
print(next(kv2))
print(next(kv2))
从小到大排序:sorted(list)
从大到小排序:sorted(list,reverse=True)
# -*- coding: utf-8 -*-
# !/usr/bin/python3
# author by : yuxiangShi
# tell by: 18538187569
alist = [0, 10, 88, 19, 9, 1]
print(sorted(alist))
print(sorted(alist, reverse=True))
alist.sort()
print(alist)
alist.sort(reverse=True)
print(alist)
输出:
[0, 1, 9, 10, 19, 88]
[88, 19, 10, 9, 1, 0]
[0, 1, 9, 10, 19, 88]
[88, 19, 10, 9, 1, 0]
比较相邻的元素,如果第一个比第二个大,就交换
一轮遍历,每两相邻元素,重复1,最大放队尾
不包括已经排队尾,重复2
# -*- coding: utf-8 -*-
# !/usr/bin/python3
# author by : yuxiangShi
# tell by: 18538187569
# 冒泡排序
def bubble_sort(list):
# 获取数组长度
count = len(list) - 1
# N个元素遍历N次
for index in range(count, 0, -1):
# 第一个和第i+1个依次对比
for sub_index in range(index):
# 最大的元素冒上去
if list[sub_index] > list[sub_index + 1]:
list[sub_index], list[sub_index + 1] = list[sub_index + 1], list[sub_index]
return list
alist = [0, 10, 88, 19, 9, 1]
print(bubble_sort(alist))
输出:
[0, 1, 9, 10, 19, 88]
从列表中挑出一个元素,作为基准值key
所有小于key的元素放左边,所有大于key的元素放右边
分别递归左侧列表,右侧列表
# -*- coding: utf-8 -*-
# !/usr/bin/python3
# author by : yuxiangShi
# tell by: 18538187569
# 快速排序
def quick_sort(lists, left, right):
# 递归过程中,发现left和right一致时,停止递归,直接返回列表
if left >= right:
return lists
# 定义游标
low = left
high = right
# 取参考标志,最左边的元素
key = lists[low]
while low < high:
# 从最右侧向左,依次和标志元素对比,如果右侧的元素大于标志元素
while low < high and lists[high] >= key:
# 右侧减1
high = 1
# 否则low赋high值
lists[low] = lists[high]
# 从最左侧向右,依次和标志元素对比,如果左侧的元素小于标志元素
while low < high and lists[low] <= key:
# 右侧加1
low += 1
# 否则high赋low值
lists[high] = lists[low]
# 最后给high位置符值
lists[high] = key
# 处理左侧元素
quick_sort(lists, left, low - 1)
# 处理右侧元素
quick_sort(lists, low + 1, right)
return lists
alist = [0, 10, 88, 19, 1, 7]
print(quick_sort(alist, 0, 6))
堆排序指利用的数据结构设计的一种排序算法
堆近似一个完全二叉树结构
子结点的键值小于(或者大于)它的父节点
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b7KC5K4a-1633789899133)(/static/upload/bigpic/20210629/1624975894689377409.png)]
# -*- coding: utf-8 -*-
# !/usr/bin/python3
# author by : yuxiangShi
# tell by: 18538187569
def heap_sort(lst):
def sift_down(start, end):
"""最大堆调整"""
root = start
print("root %d start %d end %d" % (root, start, end))
while True:
child = 2 * root + 1
print("child index: %d" % child)
# 终止条件,孩子的索引值超过数组最大长度
if child > end:
break
print("lst child value:%d" % lst[child])
# 确定最大的孩子节点的索引值
if child + 1 <= end and lst[child] < lst[child + 1]:
child += 1
print("child+1 index: %d" % child)
# 孩子节点最大值和根节点交换
if lst[root] < lst[child]:
lst[root], list[child] = lst[child], lst[root]
print("lst root %d" % lst[root], "lst child %d" % lst[child])
root = child
print("root %d" % root)
else:
break
print("--------创建最大值--------")
# 创建最大堆
print(xrange((len(lst) - 2) // 2, -1, -1))
for start in xrange((len(lst) - 2) // 2, -1, -1):
print("---->Loop start %d" % start)
sift_down(start, len(lst) - 1)
print(lst)
print("--------排序过程----------")
# 堆排序
for end in xrange(len(lst) - 1, 0, -1):
# 首尾交换
lst[0], lst[end] = lst[end], lst[0]
# 剩余重新堆排序
sift_down(0, end - 1)
print(lst)
return lst
alist = [70, 60, 12, 40, 30, 8, 10]
print(heap_sort(alist))
二分查找又称折半查找
必须采用顺序存储结构
必须按关键字大小有序排列
# -*- coding: utf-8 -*-
# !/usr/bin/python3
# author by : yuxiangShi
# tell by: 18538187569
alist = [0, 1, 10, 88, 19, 9, 1]
def binary_search(arr, start, end, hkey):
if start > end:
return -1
mid = start + (end - start) / 2
if arr[mid] > hkey:
return binary_search(arr, start, mid - 1, hkey)
if arr[mid] < hkey:
return binary_search(arr, mid + 1, end, hkey)
return mid
alist = sorted(alist)
print(alist)
print(binary_search(alist, 0, 6, 9))
素数又称质数
0,1不是素数
除了1和它自身外,不能被其他自然数整除的数
# -*- coding: utf-8 -*-
# !/usr/bin/python3
# author by : yuxiangShi
# tell by: 18538187569
# 0,1不是素数
# 除了1和它自身外,不能被其他自然数整除的数
def is_prime(n):
if n <= 1:
return False
for i in range(2, n - 1):
if n % i == 0:
return False
return True
for i in range(0, 100):
if is_prime(i):
print(i)
[image:C0E62692-F54F-4E32-AAD0-DC732B83FBBF-275-00022443262E7424/95E38541-6E13-492C-B105-F0E2CE67127C.png][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UF7CP2KT-1633789899136)(/static/upload/bigpic/20210629/1624975957710395955.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fm0MRxQ9-1633789899138)(/static/upload/bigpic/20210629/1624975975490471642.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jrLnGsXp-1633789899141)(/static/upload/bigpic/20210629/1624975991419512239.png)]
进程:独立数据空间。进程间不共享数据,系统调度
线程:执行程序的最小单元,进程内线程间共享资源,系统调度
一个进程可以有多个线程,多个线程也可以并发执行
就绪状态:已获除处理以外所需资源,等待分配处理机资源
运行状态:占用处理机资源运行,此状态进程数<=CPU数
阻塞状态:进程等待某种条件,在条件满足之前无法执行
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6Ew7TpuZ-1633789899142)(/static/upload/bigpic/20210629/1624976019551169281.png)]
互斥:某一资源同时只允许一个访问者对其进行访问
具有唯一性和排他性
互斥无法限制访问者对资源的访问顺序,即访问是无序的
同步:基于互斥,经其他机制实现访问者对资源的有序访问
大多数情况下,同步已经实现了互斥,写入资源是互斥的
少数情况下,可以允许多个访问者同时访问资源
管道:半双工通方式,数据单项流动,父子进程间
命名管道:半双工通信方式,无亲缘关系进程间通信
信号量:是计数器,锁机制,控制多进程对资源访问
消息队列:消息链表,存放在内核中消息队列标识符标识
信号:比较复杂的通信方式,通知进程某个事件已经发生
共享内存:映射一段能被多个进程可访问的内存
先来先服务
短作业服务优先
时间片轮转调度算法
高响应优先
优先权调度算法
多级队列调度算法
资源竞争;进程推进顺序不当
必要条件:互斥,不剥夺,请求与保持,环路等待
预防死锁:破坏四个必要条件之一
最佳置换算法
先进先出置换算法
最近最久未使用置换算法
Clock置换算法,也叫最近未使用算法
最少使用置换算法
定义规则,指定哪些文件先翻译、后编译、重新编译
Makefile的好处,自动化编译
makefile需要make工具解释执行
虚存(VIRT=SWAP+RES):进程“需要的”虚拟内存大小
包括进程使用的库、代码、数据,以及malloc、new分配的堆空间和分配的栈空间等
申请10MB,使用1MB,增长10MB
实存(RES=CODE+DATA):
包括使用中的malloc、new分配的堆空间和分配的栈空间,但不包括swap out量
申请10MB,使用1MB,增长1MB
共享内存(SHR):自身,也包括其他进程的共享内容
进程只使用了几个共享库的函数,但包含真个共享库大小
某个进程所占的物理内存大小:RES - SHR
Activity:程序与用户的交互窗口
Service:在程序后台,完成用户的操作
ContentProvider:提供数据的统一访问格式
BroadcastReceiver:应用程序之间传输信息的机制
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7Y8sEjQY-1633789899145)(/static/upload/bigpic/20210629/1624976053908291096.png)]
ANR:Application Not Responding
Actiivity的最长执行时间是5秒
用户可以选择“等待”让程序继续运行,或“强制关闭”
FrameLayout(框架布局)
LinearLayout(线性布局)
AbsoluteLayout(绝对布局)
RelativeLayout(相对布局)
TableLayout(表格布局)
Tween动画,组件移动、缩放、透明度的变化
Frame动画,通过顺序播放来实现,类似电影
adb kill-server # 停止服务
adb start-server # 启动服务
adb -s <devicename> install <path-to-apk> # 安装
adb -s <devicename> install -r <path-to-apk> # 安装
adb -s <devicename> uninstall <packagename> # 卸载
adb push *.apk /data/local/tmp/*.apk
adb pull /data/local/tmp/*.apk *.apk
adb push *.apk /data/local/tmp/*.apk
adb shell pm install -f /data/local/tmp/*.apk
adb shell am start -W -S package/activiy
adb shell am force-stop package
adb shell pm list package -f keyword
adb shell pm list package -3 keyword
adb shell pm list package -i keyword
adb shell screencap /data/local/tmp/screen.png
adb shell screenrecord /data/local/tmp/demo.mp4
adb logcat
adb shell logcat
adb shell dumpsys meminfo package
adb shell dumpsys cpuinfo | findstr package
adb shell monkey -p <packagename> <count>
添加参数 -s seed
将monkey执行过程中的日志重定向到文件
测试版App连接第三方统计平台
添加参数 --throttle
添加忽略Crash参数 --ignore-crashes
添加忽略ANR参数 --ignore-timeouts
触摸事件—pct-touch
动作事件—pct-motion
轨迹球事件—pct-trackball
基本导航事件—pct-nav
主要导航事件—pct-majornav
系统导航事件—pct-syskeys
应用启动事件—pct-appswitch
其他类型事件—pct-anyevent
功能性测试
Activity生命周期的测试
模拟数据库操作的测试和兼容性测试
使用Java JUnit框架
需要进行白盒测试时
需要使用mock技术模拟系统对象时
UIAutomator是Android UI自动化测试工具
不需要源码,基于Java开发语言
UiDevice,UiSelector,UiScrollable,UiObject,UiCollection
APP UI层的交互操作
不需要源码,可以模拟跨进程过程
基于Java JUnit框架,黑盒UI自动化
UiAutomatorViewer
可以识别元素的id、classname、bounds等
Selendroid Client:Webdriver + 移动特性的实现
Selendroid Server:一个Instrumentation APK
AndroidDriver-App:一个WebViewActivity,即浏览器
Selendroid-Standalone:大总管,负责准备环境
基于Instrumentation进行封装,实现的Android测试框架
封装了一个Solo类库,提供自动化测试API
由于是基于Instrumentation,测试时需要源码
一个开源的移动端UI自动化测试框架
不需要App源码
不局限于语言或者框架
接口统一,不需要重复开发
必须是开源的
C/S架构,Appium核心是一个web服务器
Session,客户端初始化session与服务端交互
Desired Capabilites,初始化时的键值对组合
Appium Server,操作与驱动手机的
Appium Client,支持多语言调用
Android SDK、JDK、Appium
Pycharm、Python环境
库:Selenium、Appium-Python-Client
Java、Javascript、PHP、Python
Ruby、C#、Perl、Object C
platformName,目标设备平台Android/iOS
platformVersion,目标设备的平台版本
appPackage,App包名(Android)
AppActivity,App Activity名称(Android)
automationName,自动化启动类型Selendroid/Appium
unicodeKeyboard,是否使用Appium输入法
resetKeyboard,是否恢复默认键盘
第一个选择,使用UIAutomatorViewer
第二个选择,使用Appium的Inspector
find_element_by_accessibility_id
find_element_by_id
find_element_by_name
find_element_by_xpath
find_element_by_class_name
LOVE规则
L:Locate定位
O:Operate操作
V:Verify验证
E:Exception异常的处理
不需要指定App的包路径
默认使用Appium驱动
如果需要输入中文,需要添加输入法相关的配置
Native部分,UIAutomator或者Appium Inspector
WebView部分,Chrome浏览器的调试模式
find_element_by_id
find_element_by_name
find_element_by_xpath
find_element_by_link_text
find_element_by_tag_name
find_element_by_class_name
find_elements_by_id
find_elements_by_name
find_elements_by_xpath
find_elements_by_link_text
find_elements_by_tag_name
find_elements_by_class_name
S-LOVE规则
S:Switch
L:Locate定位
O:Operate操作
V:Verify验证
E:Exception异常的处理
需要明确指定驱动名称为:Selendroid
需要明确指定App的路径,因为需要重签名
工具:Pycharm、chrome
包:selenium、Python
webdriver:chrome driver/firefox driver/ie driver等
firefox或者chrome的调试工具
find_element_by_id
find_element_by_name
find_element_by_xpath
find_element_by_link_text
find_element_by_tag_name
find_element_by_class_name
find_elements_by_id
find_elements_by_name
find_elements_by_xpath
find_elements_by_link_text
find_elements_by_tag_name
find_elements_by_class_name
IDE:PyCharm
包:Python、Selenium、Appium-python-client
工具:Appium、Chrome
chrome浏览器调试wap页面
初始化时,指定browsername为:Browser
自动化测试代码和selenium代码相同
TestFirxture:setUp、TestCase、TearDown
# -*- coding: utf-8 -*-
# !/usr/bin/python3
# author by : yuxiangShi
# tell by: 18538187569
import unittest
class MyTestCase(unittest.TestCase):
# 每条用例初始化
def setUp(self) -> None:
self.initdata = "hello imooc"
# 测试用例、以test开头
def test_something(self):
self.assertEqual("hello imooc", self.initdata)
# 每条用例执行完后释放资源
def tearDown(self) -> None:
pass
if __name__ == '__main__':
# 声明一个suite
suite = unittest.TestSuite()
# 从类加载用例集
cases = unittest.TestLoader().loadTestsFromTestCase(MyTestCase)
# 添加用例到suite
suite.addTests(cases)
# 声明TestRunner
myTestRunner = unittest.TextTestRunner(verbosity=2)
# 执行Runner
myTestRunner.run(suite)
TestCase
TestSuite
TestRunner
数据驱动测试,即黑盒测试,又称为功能测试
数据驱动单元测试为数据源中的每行重复进行一种单元测试
数据驱动单元测试,常用情况是使用多个输入值测试API
Python下的数据驱动框架名称也叫DDT(Data-Driven Tests)
效果:使用多个数据运行一条用例,使其表现为多条用例
原理:通过Python的装饰器、装饰每条用例
# -*- coding: utf-8 -*-
# !/usr/bin/python3
# author by : yuxiangShi
# tell by: 18538187569
import unittest
from appium import webdriver
from ddt import ddt, data
import time
@ddt
class MyTestCase(unittest.TestCase):
# 初始化
def setUp(self) -> None:
desired_caps = {'platformName': 'Android', 'platformVersion': '5.1', 'deviceName': '192.168.56.102:5555',
'browerName': 'Browser', 'unicodekeyboard': 'True', 'resetKeyboard': 'True'}
self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
# 释放资源
def tearDown(self) -> None:
self.driver.quit()
@data(u"Android 专项测试 Python篇", u"Javascript")
def test_searchkeyword(self, keyword):
# 打开首页
self.driver.get('http://www.imooc.com')
# 等待加载完成
time.sleep(3)
# 定位输入框
input = self.driver.find_element_by_xpath("/html/body/header/div/input")
# 定位搜索按钮
button = self.driver.find_element_by_xpath("/html/body/header/div/form/div/div/button")
# 点击搜索
button.click()
# 等待页面加载完成
time.sleep(3)
# 定位搜索结果的首条
result0 = self.driver.find_element_by_xpath('//*[@id="pages-container"]/div/div[1]/dl/dd[1]/a/div/p[1]')
# 验证包含关键词
self.assertTrue(keyword in result0.text)
if __name__ == '__main__':
suite = unittest.TestSuite()
cases = unittest.TestLoader().loadTestsFromTestCase(MyTestCase)
suite.addTest(cases)
myTestRunner = unittest.TextTestRunner(verbosity=2)
myTestRunner.run(suite)
代码复用率高,一次编写多条数据复用逻辑
异常排查效率高,测试执行隔离,数据间无影响
代码可维护性高,提高代码的易读性
行为驱动开发,Behavior-Driven Development,简写BDD
在软件工程中,BDD是一种敏捷开发的技术
Lettuce是基于Python语言的行为驱动测试框架
Lettuce将测试用例和自动化测试代码分离
Lettuce写测试用例就像写文本一样清晰
行为驱动测试实例
关键词驱动测试也称为表格驱动测试或行动驱动测试
它将创建测试程序的步骤分为规划及实现二个阶段
关键词驱动使不懂代码的人可以完成自动化过程
基于RIDE可视化工具,导入AppiumLibrary
使用AppiumLibrary中提供的关键词,实现用例过程
使用RIDE完成用例的执行与结果的管理
持续集成是指开发阶段,对项目进行持续性
自动化编译、测试,以达到控制代码质量的手段
持续集成是一种软件开发实践
开发人员、版本控制
CI服务器、构建脚本
反馈机制、集成构建
减少分险、减少重复过程
任何时间、任何地点生成可部署的软件
增强项目可见性、建立团队对开发产品的信心
Jenkins、Buildbot
Travis CI、Strider
Go、Integrity
下载Jenkins.war
命令行运行:java -jar jenkins.war
在浏览器窗口打开:http://localhost:8080
系统级配置
工程级配置
LoadRunner
JMeter
自主研发的工具
CPU
内存(虚存、实存)
QPS、平均相应时间
搭建服务端模块、并启动服务
监控进程相关指标,内存、CPU
监控模块的执行情况,QPS、平均相应时间
收集数据并进行分析,生成曲线图
根据分析结果,得出测试结论
系统版本(Android&IOS平台,不同版本)
分辨率(小屏、大屏、全屏)
手机品牌(华为、小米、OPPO、VIVO等)
不同平台的不同浏览器(safari、chrome等)
分辨率(小屏、大屏、全屏)
转发到QQ、微信、微博等第三方平台
操作系统(常用windows、Mac os、平板电脑)
浏览器(IE系列、firefox、chrome等)
分辨率(笔记本、台式机、窗口缩放等)
网络相关工具,fiddler、wareshark、Charles
adb、am、logcat等
云平台,bug复现
Chrome调试工具,可设置移动App UA
WINRE,Web Inspector Remote
Chrome调试工具
火狐的firebug
博客来源:雨夜的博客