自研测试框架ktest介绍(适用于UI和API)
iTesting,爱测试,爱分享
在自动化测试的过程中,测试框架是我们绕不过去的一个工具,无论你是不需要写代码直接改动数据生成脚本,还是你需要检查测试结果甚至持续集成,测试框架都在发挥它的作用。
不同编程语言的实现出来的框架也不尽相同,但是思想总是相通的,比如尽量使框架使用者只关注自己的业务,框架帮助处理错误截图,保存错误log,出错重试甚至跟jenkins持续集成等。
可以说,一个还算合格的测试框架,可以大大提升测试效率;一个优秀的测试框架,说它能把测试人员从繁缛复杂的跟业务无关但又不得不做的工作中解脱出来也不为过。既然框架的作用这么明显,那么有哪些优秀的测试框架可以给我们用呢?
大家都知道, java里有TestNG, python里有unittest,pytest等优秀的“官方”框架, 我对python比较熟悉,之前也介绍过很多这方面的文章,相信大家也多少看过一两篇。
那么,为什么还要自己写一个框架呢?
相信常做自动化的都有自己的感悟, 比如自己业务没那么复杂,官方框架显得太重了;比如官方框架依赖很多的第三方库,每个要单独安装,更新,而且每个都有自己的用法,学习成本高;
痛点:
对于常用python写自动化的来说,unittest本身很优秀,但是不支持并发,而且测试报告支持的也不好,也不支持数据驱动。
解决方案:
基于上述痛点,大部分同学选择在原有开源框架上二次开发,比如unittest集合多线程threading.Thread实现并发,加入HTMLTestRunner实现报告展示,引入ddt实现数据驱动,然后美其名曰,我写了个框架,我每次听到都是先很崇拜,然后晚上暗搓搓拉下代码一看,MD,这不是就是搭了个积木取名要你命3000吗?你还不能说人家说自己写了一个框架不对,何况这个框架通常也很好用。
再有,开源的框架,毕竟普适多于贴合,跟自己的业务有时候就不那么紧密,为了使用某个具体功能还得引入很大一个包,也不是非常方便,另外最关键的一点是,我总觉得自己还行,想站起来试试 :)
框架是什么?我是怎么考虑框架的?
之前分享过几篇文章,
这些都是我工作的一些感悟,和对框架的一些思考,可以看到思想也是循序渐进的。你也可以看到不是“官方”框架,就是二次开发的“官方”框架。 当然也可以说我是常怀觊觎之心,不停研究的目的就是我个人非常想有一套完全自己实现的框架。
什么是ktest?
一句话:
ktest is a common test framework support for Both UI and API test with run in parallel ability。
跟其它的框架有什么不同?
参考了谁?
我当然不是闭门造车,参考了unittest,pytest,ddt,还有自己公司的官方框架, 读了部分源码,研究了下部分功能实现原理。
实现的功能:
1.多线程并发。(整套框架代码没出现任何哪怕一句threading,实现了并发,神奇不,嘿嘿)
详细介绍
先不介绍技术细节, 先把自己放在一个业务测试,或者刚接触自动化脚本的测试角色上,我拿到了一个测试框架,我最先想到的是什么? 如何用对吧? 用这个框架,我原有的测试用例需要做哪些改变?这个框架有哪些方便?你对框架的期待有哪些?
下面就详细介绍:
安装:
1#目前部署在自己公司的pypi库上,后期会上传到pypi。
2pip install ktest --index-url http://jenkin.xxxx.com:8081/pypi --trusted-host jenkins.xxxx.com
3#安装好后,你可以在 Python安装目录下的如下文件找到安装的包\Lib\site-packages
你的项目应该包括哪些:
在讲用法前,我们先来直观看下,你的项目目应该是什么样子的
你的项目中应该包含:
1.pages package, 这里面放你所有待测试页面,每个页面作为一个page object来保存。
可以看到,你只需要把精力放在你本身的业务上就好了。
ktest框架组成
package建立好了,我的测试用例,及我的待测页面要如何组织才能接入框架呢? 别急,我们先来看看框架本身长什么样子。
功能列表
看用红框标记起来的部分:
Common – 框架精华
1.欢迎关注公众号iTesting,跟万人测试团一起成长。
utiilites -- 拿来即用测试套件
这里面放一些半成品,比如连接数据库脚本,比如用excel做数据驱动,对excel进行读写的脚本。 用户不需要操心连接的建立,销毁等。
main.py 用来运行框架,并发运行控制也是在这里。并发我“舍弃”了threading.Thread, 代码量下降一半以上,且不用操心锁。
setup.py 用来把框架打包。
集成你的项目
1#bai_du.py
2#coding=utf-8
3__author__ = 'iTesting'
4import time
5from common.abstract_base_page import AbstractBasePage
6from page_objects import page_element
7class BAI_DU(AbstractBasePage):
8 BAI_DU_HOME = "http://www.baidu.com"
9 SEARCH_DIALOG_ID = "kw"
10 SEARCH_ICON_ID = "su"
11 MEMBER_COUNT_XPATH = "//option[@value='10']"
12 SAVE_XPATH = ".//*[@id='save']"
13 search_input_dialog = page_element(id_=SEARCH_DIALOG_ID)
14 search_icon = page_element(id_=SEARCH_ICON_ID)
15 member_count = page_element(xpath=MEMBER_COUNT_XPATH)
16 save_button = page_element(xpath=SAVE_XPATH)
17 def __init__(self, browser):
18 self.browser = browser
19 AbstractBasePage.__init__(self, browser)
20 def is_target_page(self):
21 self.browser.get(self.BAI_DU_HOME)
22 print(self.is_element_displayed_on_page(self.search_icon))
23 return self.is_element_displayed_on_page(self.search_icon)
24 def search(self, search_string):
25 self.search_input_dialog.send_keys(search_string)
26 self.search_icon.click()
27 time.sleep(5)
28 def preferences(self):
29 browser = self.browser
30 browser.get(self.BAI_DU_HOME + "/gaoji/preferences.html")
31 self.member_count.click()
32 time.sleep(1)
33 self.save_button.click()
34 time.sleep(1)
35 browser.switch_to_alert().accept()
每一个你的测试类(待测页面)你需要:
你的tests package下测试用例定义
1# test_baidu.py
2#coding=utf-8
3from common.selenium_helper import SeleniumHelper
4from common.test_case_finder import data_provider
5from common.test_decorator import TestClass, SetUpClass, Test, TearDownClass
6from pages.baidu import BAI_DU
7@TestClass(group='smoke', enabled=True)
8class TestBaidu:
9 test_case_id = '3'
10 @SetUpClass()
11 def before(self):
12 pass
13 def setUp(self):
14 self.browser = SeleniumHelper.open_browser('firefox')
15 self.baidu = BAI_DU(self.browser)
16 @data_provider([('baidu',), ('google',)])
17 @Test()
18 def test_baidu_search(self, x):
19 self.tag= 'tt'
20 """Test search"""
21 self.baidu.search(x)
22 assert 1== 1
23 @Test()
24 def test_baidu_set(self):
25 """Test set preference"""
26 print('NONONO')
27 self.baidu.preferences()
28 assert 1==0
29 def tearDown(self):
30 self.browser.delete_all_cookies()
31 self.browser.close()
32 @TearDownClass()
33 def after(self):
34 pass
注意事项
2.tags: 是每个用例的tag,定义在类属性里,test_finder查找时会解析这个tags,可以是str或者list或者tuple,或者是3者的嵌套。 框架最终会解析成一个list。
3.@SetUpClass(), @TearDownClass() 测试类装饰器,无输入参数。 每个测试类,不管它有多少个测试用例,这两个装饰器装饰的函数只会被执行一次。 一般用作测试类公用的数据的初始化,比如说,连接db查找某些值。 请注意, 并发运行,不要在这个函数里初始化你的browser,会有共享问题。
4.@TestClass(), 测试类的装饰类, 函数接受两个个参数一个是group,就是测试类所属的group,一个是enabled,默认值True。 值为False时, test_finder会把这个测试类略过。
5.@Test(), 测试装饰类, 函数接受一个参数enabled,默认值True。 值为False时, test_finder会把这个测试函数略过。
6.@data_provider(), 数据驱动装饰器。 接受一个参数,且此参数必须要iterable. 因为是数据驱动,不太可能只有一个数据,所以这个iterable,我通常我会定义成一个tuple,如果 有多个就是多个tuple, 例如[(1,2,3),(4,5,6)]这种,(1,2,3)会被解析成一条测试数据, (4,5,6)会被解析成另外一条。 这个概念来自ddt,我之前也介绍过相关框架。
7.@setUP(), @tearDown().两个函数,每个测试类必须定义,否则运行时框架会报错。 用作每个测试类的测试函数即每一条测试用例的运行前初始化和运行后的清理。
测试函数,就是以@Test()装饰的函数,一般是你的业务代码,你需要自己实现业务流程的操作和断言。如果用到setUpClass或者setUp里的方法属性,你只需要在这些属性前加self.
以上基本参照了pytest和unittest的用法,主要初衷也是为了减少迁移成本。
好,我测试类,测试函数都写好了,如何跑呢?
可用参数
1#最简单在命令行里输入ktest 即可, 框架会自动查询所有你项目文件下tests文件夹的测试用例。
2#ktest还支持如下参数:
3usage: ktest [-h]
4 [-t test targets, should be either folder or .py file, this should be the root folder of your test cases or .py file of your test classes.]
5 [-i user provided tags, string only, separate by comma without an spacing among all tags. if any user provided tags are defined in test class, the test class will be considered to run. | -ai user provided tags, string only, separate by comma without an spacing among all tags. only all of user provided tags are defined in test class, the test class will be considered to run.]
6 [-e user provided tags, string only, separate by comma without an spacing among all tags,if any user provided tags are defined in test class, the test class will be Excluded. | -ae user provided tags, string only, separate by comma without an spacing among all tags. all the provided tags must defined in test class as well.]
7 [-I include groups, string only, separated by comma for each tag. if any user provided groups are defined in decorator on top of test class, the test class will be considered to run. | -AI exclude groups, string only, separated by comma for each tag. all user provided groups are defined in decorator on top of test class, the test class which match will be excluded to run.]
8 [-E exclude groups, defined in decorator on top of test class, string only, separated by comma for each tag. If any user provided groups are defined in decorator on top of test class, the test class will be Excluded to run | -AE exclude groups, defined in decorator on top of test class, string only, separated by comma for each tag. All user provided groups must defined in decorator on top of test class. the test class which matched will be Excluded to run]
9 [-n int number] [-r dir]
其中:
1-t 是你要运行的测试目标的根目录,默认是项目下的tests文件夹。
2-i 是测试类里定义的tags。 tags会被解析成list,用户指定的任何tag只要包含在这个lists里,并且这个测试函数所属的TestClass()是enabled和这个测试函数的enabled是True,就表示这个测试类的这个测试函数会被test_filder找到。
3-I 是装饰测试类的@TestClass()定义的group,包含两个参数, 符合用户指定的group并enabled, 那么它装饰的类会被当作一个测试类被test_finder找到。
4-e 是测试类里定义的tags。 tags会被解析成list。 用户指定的任何tags包含在list里,这个测试函数就会被test_finder忽略。
5-E 是测试类里定义的tags。 tags会被解析成list。 用户指定的任何tags包含在list里,这个测试函数就会被test_finder忽略。
6-n 并发执行的个数,默认是cpu_count。
7-r 错误重跑, 默认是True。重跑再错误,所有跟case相关的log和screenshot会被记录。
Note:
有的同学会问了,我希望跑同时包括test和regression在内这两个tags的用例呢? 谁提出的这个需求?我真想指着你的鼻子说:
1# 定义了tag和group的更加严格版。只有用户输入的参数全部包含在测试用例定义的tags里,这个测试用例才会被test_finder扫描到。
2 -ai user provided tags, string only, separate by comma without an spacing among all tags. only all of user provided tags are defined in test class, the test class will be considered to run.
3 Select test cases to run by tags, separated by comma,
4 no blank space among tag values. all user provided
5 tags must defined in test class as well. tags are
6 defined in test class with name <tags>. eg: tags =
7 ['smoke', 'regression']. tags value in test class can
8 be string, tuple or list.
9
10 -ae user provided tags, string only, separate by comma without an spacing among all tags. all the provided tags must defined in test class as well.
11 Exclude test cases by tags, separated by comma, no
12 blank space among tag values. all of the tags user
13 provided must in test class as well. tags are defined
14 in test class with name <tags>. eg: tags = ['smoke',
15 'regression']. tags value in test class can be string,
16 tuple or list.
17
18 -AI exclude groups, string only, separated by comma for each tag. all user provided groups are defined in decorator on top of test class, the test class which match will be excluded to run.
19 Select test cases belong to groups, separated by
20 comma, no blank space among group values. All user
21 provided group must defined in decorator on top of
22 test class, the test class which match will be
23 collected. groups are defined in decorator on top of
24 test class. eg: group= 'UI'.
25
26 -AE exclude groups, defined in decorator on top of test class, string only, separated by comma for each tag. All user provided groups must defined in decorator on top of test class. the test class which matched will be Excluded to run
27 Exclude test cases belong to groups, separated by
28 comma, no blank space among group values. All of
29 groups user provided must defined in decorator on top
30 of test class as well. groups are defined in decorator
31 on top of test class. eg: group= 'UI'.
事实上, 为避免用法繁琐及方便用户, -i 和-ai, -e和-ae, -I和-AI, -E和-AE 是两两互斥的, 你只能指定其中的一个。
测试报告
下面我们看下一个运行实例
1ktest -I group -n 10 -r True
2执行中console的输出:
执行中console的输出:
执行成功后报告的展示:
report会自动生成在你项目根目录下,以运行时时间戳为文件夹,每个测试用例一个子文件夹。
测试报告加入了run pass, run fail, run error的图表。 run fail代表真正的fail, run error代表代码有问题或者环境问题导致的错误。同样报告直接按照测试类filter。
后记:
到此为止,ktest基本成型,也能根据需求完成web UI自动化和API自动化的工作了,不同无非是你在setUP初始化你的driver时候初始化的是你的browser还是request.session. 如果你想实现分布式并发,也可以在setUP initial selenium Grid, 前提是配置好selenium-server。
还是有一些感悟:
1.框架真不是一蹴而就的,是逐渐演化的。 最后成型的这一版跟我初始的规划还是有很大差距,有些代码甚至是不得已的妥协,比如我要出html报告,就要很多测试函数无关的数据收集,那么这些数据势必会侵入我的代码,结果就是我返回的测试函数数据结构很不简洁。
彩蛋:
放部分代码段:
test_finder部分代码:
测试类装饰器代码
关于更多技术实现细节,我会重新写一篇文章介绍。更多测试框架技术分享,请往下拉。
- End -
作者:
Kevin Cai, 江湖人称蔡老师。
两性情感专家,非著名测试开发。
技术路线的坚定支持者,始终相信Nobody can be somebody。
· 猜你喜欢的文章 ·
自研测试框架ktest介绍(适用于UI和API)的更多相关文章
- [原创]移动安全测试框架MobSF介绍
[原创]移动安全测试框架MobSF介绍 1 mobsf简介 Mobile Security Framework (移动安全框架) 是一款智能.集成型.一体化的开源移动应用(Android/iOS)自动 ...
- python nose测试框架全面介绍十---用例的跳过
又来写nose了,这次主要介绍nose中的用例跳过应用,之前也有介绍,见python nose测试框架全面介绍四,但介绍的不详细.下面详细解析下 nose自带的SkipTest 先看看nose自带的S ...
- python nose测试框架全面介绍七--日志相关
引: 之前使用nose框架时,一直使用--logging-config的log文件来生成日志,具体的log配置可见之前python nose测试框架全面介绍四. 但使用一段时间后,发出一个问题,生成的 ...
- python nose测试框架全面介绍六--框架函数别名
之前python nose测试框架全面介绍二中介绍了nose框架的基本构成,但在实际应该中我们也会到setup_function等一系列的名字,查看管网后,我们罗列下nose框架中函数的别名 1.pa ...
- python nose测试框架全面介绍五--attr介绍
之前写了一系列nose框架的,这篇介绍下attr tag 在nose框架中attr用来标识用例,使得在运行时可以通过标识来执行用例,之前在nose测试框架全面介绍四中有说明,但没有说明清楚,这里再总结 ...
- 爬虫、网页测试 及 java servlet 测试框架等介绍
scrapy 抓取网页并存入 mongodb的完整示例: https://github.com/rmax/scrapy-redis https://github.com/geekan/scrapy-e ...
- python nose测试框架全面介绍三
三.nose的测试工具集 nose.tools模块提供了一系列的小工具,包括测试执行时间.异常输出及unittest框架中所有的assert功能. 为了使写用例更加容易,nose.tools提供了部分 ...
- python nose测试框架全面介绍一
一.简介 nose 是python自带框架unttest的扩展,使测试更简单高效:nose是一个开源的项目,可以在官网上下载源码 1.快速安装 有以下几中安装方式: easy_install ...
- python nose测试框架全面介绍十二 ----用例执行顺序打乱
在实际执行自动化测试时,发现我们的用例在使用同一个资源的操作时,用例的执行顺序对测试结果有影响,在手工测试时是完全没法覆盖的. 但每一次都是按用例名字来执行,怎么打乱来执行的. 在网上看到一个有意思的 ...
随机推荐
- 富文本编辑器Tinymce的示例和配置
Demo链接: https://download.csdn.net/download/silverbutter/10557703 有时候需要验证tinyMCE编辑器中的内容是否符合规范(不为空),就需 ...
- Django搭建后篇——启动服务器及创建视图
开启服务器,Django开启服务器的方式有两种,一种是在Ubuntu在开启,另一种是直接在pycharm开启.就方便而言肯定是第二种,但由于pycharm版本的问题,可能有的人无法直接在pycharm ...
- SQL注入常用函数(注入小白的学习笔记)
在盲注的情况下,往往需要一个一个字符的去猜解,即过程中需要截取字符串 在这里整理了一下一些常用函数 由于现阶段学习不够深入,整理分类不清楚具体,不过博主会慢慢进行完善 user() 查询当前数据库用户 ...
- 关于汽车诊断OBD的理解(ISO15031-5)(转发)
1.OBD用来做什么 2.OBD和UDS的区别 3.OBD硬件接口简介 4.OBD的9大模式介绍 OBD(On-Board Diagnostic)指的是在线诊断系统,是汽车上的一种用于监控车辆状况以及 ...
- Maven打包时报Failed to execute goal org.apache.maven.plugins:maven-war-plugin:解决方案
问题现象: 用Maven打包时,报Failed to execute goal org.apache.maven.plugins:maven-war-plugin:2.2:war错误. 原因分析: 打 ...
- android简洁饼状图组件、圆形Menu菜单、画板画笔应用、答题应用等源码
Android精选源码 android自动监听复制内容源码 Android上简洁轻量级的饼图控件 好看的 Android 圆形 Menu 菜单效果 android画笔.画板功能效果的实现 Androi ...
- Exception in thread "main" java.lang.AbstractMethodError
参考https://stackoverflow.com/questions/15758151/class-conflict-when-starting-up-java-project-classmet ...
- space sniffer
space sniffer 一款检测本地磁盘文件占用情况的工具,高效,快速.
- [LC] 90. Subsets II
Given a collection of integers that might contain duplicates, nums, return all possible subsets (the ...
- 不同SQL数据库之间表数据的实时同步-发布与订阅
https://blog.csdn.net/rand_muse/article/details/81326879 上述文章中,如果是实时同步,选择 事务发布即可 在快照代理 那里,不需要勾选 运行 ...