博客园的markdown是屎!! 你可以选择去简书阅读:https://www.jianshu.com/p/537156a52250
这周我们继续这个系列,这是最后一篇。建议先阅读前两篇文章。
使用“数据驱动测试”之前应该知道的
使用“数据驱动测试”之前你应该知道的(二)
其实,我以前一直按照第二篇文章所介绍的方式写用例,写过UI自动化(200+用例),也写接口自动化用例(500+用例),接口自动化第一版是用PHP写的,当时还没用到参数化,第二版用python重写才用到了parameterized做参数化,结果大大缩减了测试代码的行数。我不认为把接口参数写到用例里有什么不妥。因为接口测试有数据的初始化动作,所以,接口用例很稳定,只要用例失败一准是接口处理逻辑变动了,接口自动化项目被我维护了两年,直到后来离职。之所以说这些,只是想说明我的观点至少不是写两个demo总结出来的。
直到最近,我在亚马逊上看到一本书《Selenium Framework Design in Data Driven Testing》,评价挺高,经过一翻查找,有同学将这本书第十章的例子放到了GitHub上。
https://github.com/PacktPublishing/Selenium-Framework-Design-in-Data-Driven-Testing
整本书基于Java语言,基于TestNG单元测试框架的DataProvider来实现读JSON数据文件。所以,读数据文件是不能脱离单元测试框讨论的,因为它确实解决了用代码写测试用例的大部分问题。
既然这样,那python下面的单元测试框架unittest/pytest是否也有类似的操作,不用那么麻烦就可以把文件中的数据读出来并参数化到测试用例中。
同样以登录功能为例,这里将介绍支持unittest的ddt库。
首先创建一个数据文件:test_ddt_file.json
{
"test_login_01":{
"username":"",
"password":"123",
"assert_text": "请输入帐号"
},
"test_login_02":{
"username":"user",
"password":"",
"assert_text": "请输入密码"
},
"test_login_03":{
"username":"error",
"password":"error",
"assert_text": "帐号或密码错误"
},
"test_login_04":{
"username":"admin",
"password":"admin123456",
"assert_text": "admin你好"
}
}
创建测试用例:
import unittest
from selenium import webdriver
from ddt import ddt, file_data
from time import sleep
@ddt
class TestLogin(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.driver = webdriver.Chrome()
cls.url = "http://127.0.0.1:8000/"
cls.driver.implicitly_wait(10)
@classmethod
def tearDownClass(cls):
cls.driver.quit()
def user_login(self, username, password):
driver = self.driver
driver.get(self.url)
driver.find_element_by_id("inputUsername").send_keys(username)
driver.find_element_by_id("inputPassword").send_keys(password)
driver.find_element_by_id("Login").click()
@file_data("./test_ddt_file.json")
def test_login(self, username, password, assert_text):
self.user_login(username, password)
if username == "admin":
sleep(2)
tips = self.driver.find_element_by_id("user").text
self.assertEqual(tips, assert_text)
else:
tips = self.driver.find_element_by_id("tips").text
self.assertEqual(tips, assert_text)
if __name__ == '__main__':
unittest.main()
注意看文件的读取,只需要通过@file_data装饰器指定数据文件的路径就好。只能方便到这种程度了。那么这是不是就是完美的了?
首先,一个测试文件只能放一种类型的数据。
"test_one": [1, 2, 3],
"test_two": "split",
"test_three": {"three": 3},
"test_four": {"four": 4, "five": 5}
上面这种格式的数据肯定是不行的,因它们的数据格式是不一致。所以,我们要分四个文件分别存放这四条用例数据。
难道要自动化的项目只有登录么?肯定不是,不同的功能点用到的数据是不一样的。
- 1、搜索功能:名称
- 2、添加地址功能:名称、地址、人数、日期
- 3、签到功能:手机号
- 4、添加嘉宾功能:姓名、手机号、邮箱
- 5、.....
你需要为每一个涉及到数据的功能点创建一个数据文件。如果系统有50个这样的功能呢!需要创建50个数据文件。当需要维护用例的时候,你需要分两步,第一步先找到用例代码,然后,再根据名称找到对应的数据文件增加或删除一条用例,再切会到用例代码使其运行通过...
……
@data(["", "123", "请输入帐号"],
["user", "", "请输入密码"],
["error", "error", "帐号或密码错误"],
["admin", "admin123456", "admin你好"],
)
def test_login_2(self, username, password, assert_text):
self.user_login(username, password)
if username == "admin":
sleep(2)
tips = self.driver.find_element_by_id("user").text
self.assertEqual(tips, assert_text)
else:
tips = self.driver.find_element_by_id("tips").text
self.assertEqual(tips, assert_text)
……
为何不把数据和用例绑定在一起,这样不管是改用例,还是改数据都是一目了然的事情。
> 你可能会站出来说,可是用数据文件管理数据,不懂代码也可以写做自动化用例,你连代码都不想看懂的人还想做自动化测试?梁静茹给你的“勇气”?
> 你又接着说,如果有一万条数据,不能都把这些数据写代码里对吧!可拉倒吧,一万条数据确定是功能功能转过来的自动化用例?能举例出你所测试的哪个功能是需要手功执行一万条数据的么?不能!就别YY这种需求了。你怕不是和性能测试数据搞混了吧!?
> 你又说,如果一条数据很长呢?比如测试文本框的最大字符限制(500或20000),这500个字都写代码里肯定不优雅。好吧!你能举的也就这么个例子了。其实,500字放到数据文件里也优化不到哪儿去。为何不写个for循环生成500个字呢?20000个也是秒秒钟的事呀!
本文写作的是带有一些个人情绪在里面的,因为我看到那些上来就教测试新手读取excel文件的,甚至把用例都写到excel文件的行为是不认同的。
这玩意,你做的有QTP专业么?QTP的份额还不是在下滑。开源的 robot Framework已经封装的那么好了,过了那个风口,现在还不是不温不火。因为业务场景是复杂多变的,前端开发技术的更新,也会倒逼自动化技术的演变。不然,功能测试人员早被自动化测试取代了。
要想把自动化技术做好,好老老实实的锻炼自己的编程技术,从设计模式,代码架构,方法封装几个方面把你的自动化化测试项目做的足够灵活和可维护。
别整天跟风,看到别的测试人员随便封装了所谓的“测试框架”,你就好奇心爆棚的学两下,写两个demo,然后就丢一边了。
难道不应该潜下心好好分析自己测试的业务,哪些适合做UI,哪些适合做接口,哪些适合写一些脚本,或做一个系统来提高测试效率。
上一篇文章有人说,我作为一个公众号不应该用“鄙视”这样不友善的词,那这里声明一个,虫师所有文章仅代表他个人观点,你们不认同可以喷他,与“测试圈TC”公众号无关。