在pytest框架知识点分享篇中提到分享unittest框架知识点。这里分享几个在项目实战中unittest的使用方式。
学习unittest就必须要了解unittest框架4个重要的概念:test fixture、test case、test suite和test runner,只有理解了这几个概念才能理解单元测试的基本特征。
Test Case
一个TestCase的实例就是一个测试用例。什么是测试用例呢?就是一个完整的测试流程,包括测试前准备环境的搭建(setUp)、实现测试过程的代码(run),以及测试后环境的还原(tearDown)。单元测试(unit test)的本质也就在这里,一个测试用例就是一个完整的测试单元,通过运行这个测试单元,可以对某一个功能进行验证。
Test Suite
一个功能的验证往往需要多个测试用例,可以把多个测试用例集合在一起来执行,这就产生了测试套件TestSuite的概念。Test Suite用来组装单个测试用例。可以通过addTest加载TestCase到TestSuite中,从而返回一个TestSuite实例。
Test Runner
测试的执行也是单元测试中非常重要的一个概念,一般单元测试框架中都会提供丰富的执行策略和执行结果。在unittest单元测试框架中,通过TextTestRunner类提供的run()方法来执行test suite/test case。test runner可以使用图形界面、文本界面,或返回一个特殊的值等方式来表示测试执行的结果。
Test Fixture
对一个测试用例环境的搭建和销毁,就是一个fixture,通过覆盖TestCase的setUp()和tearDown()方法来实现。有什么用呢?比如说在这个测试用例中需要访问数据库,那么可以在setUp()中通过建立数据库连接来进行初始化,在tearDown()中清除数据库产生的数据,然后关闭连接等。
注意:tearDown的过程很重要,要为下一个test case留下一个干净的环境。
需要关注的是,其中fixtures机制被执行的逻辑时机:
setUpModule/tearDownModule:在整个模块的开始与结束时被执行。
setUpClass/tearDownClass:在测试类的开始与结束时被执行。
setUp/tearDown:在测试用例的开始与结束时被执行。
如有这样一段代码:
import unittest
def setUpModule():
print("test module start MMMMMMMMMMMMMM")
def tearDownModule():
print("test module end MMMMMMMMMMMMMMMM")
class MyTestFixtures(unittest.TestCase):
@classmethod
def setUpClass(cls):
print("test class start CCCCCCCCCCC")
@classmethod
def tearDownClass(cls):
print("test class end CCCCCCCCCCC")
def setUp(self):
print("test method is performed start ...")
def tearDown(self):
print("test method is performed end ...")
def test_case1(self):
print("test_case1 start ....")
def test_case2(self):
print("test_case2 start ...")
if __name__ == "__main__":
unittest.main()
执行后的结果顺序是:

需要注意的是,setUpClass/tearDownClass的写法稍有不同。首先,需要通过@classmethod进行装饰,其次方法的参数为cls。其实,cls与self并没有什么特别之处。都只表示类方法的第一个参数,只是大家约定俗成,习惯于这样来命名,当然也可以用abc来代替。在程序当中要这么写:
# -*- coding:UTF-8 -*-
from selenium import webdriver
import unittest
from time import sleep
class TestYoudao(unittest.TestCase):
@classmethod
def setUpClass(cls):
print("有道检索开始。。。")
cls.driver = webdriver.Firefox() //这里要用cls.driver
cls.driver.implicitly_wait(2)
cls.base_url = "www.youdao.com"
def test_youdao(self):
print("test_youdao ...")
self.driver.get('http://'+self.base_url) //别的方法中正常用自己的self,也就是上面是cls.base_url到测试方法里就变成了self.base_url
self.driver.find_element_by_id("translateContent").clear()
self.driver.find_element_by_id("translateContent").send_keys("selenium")
self.driver.find_element_by_tag_name("button").click()
self.driver.implicitly_wait(2)
def test_verify(self):
print("test_verify...")
title = self.driver.title
self.assertNotEqual(title,"有道首页")
@classmethod
def tearDownClass(cls):
sleep(5)
print("有道清理环境。。。")
cls.driver.quit()
if __name__ == "__main__":
unittest.main()
- 项目实战中unittest使用方式
- 新建一个类继承unittest.TestCase
Class TestCase(unittest.TestCase)
- 导入unittest
Import unittest
- 写一个以test开头的方法
Def test_01_login(self)
注:只要在pycharm的当前项目目录的setting设置中配置好了执行的环境变量路径,就能执行程序,写的main方法根本就没有执行,main就是画蛇添足,没有任何意义。
Unitest运行测试用例的一个很大的坑:
- 命令行方式
Python -m unittest 模块名.py
Python -m unittest test_case.TestCase.test_02_login
- Main方式
必须要配置环境
写购物网站框架时的技术代码思路
#查询商品
#进入菜单框架
Driver.switch_to.frame(“menu-frame”)
Driver.find_element(By.LINK_TEXT,”商品列表”).click()
#出框架
Driver.switch_to.default_content()
#进入到main的框架
Drvier.switch_to.frame(“main-frame”)
#选中所有分类下拉框中的GSM手机项(注意:这里的下拉列表选项的元素定位方法的写法)
Sel = Select(driver.find_element(By.NAME,”cat_id”))
Sel.select_by_value(“4”)
#sel.select_by_visible_text(“手机配件”)
#sel.select_by_index(“7”)
- DDT+EXCEL数据驱动
数据格式采用:excel/yaml
- 什么是DDT
Data driver test数据驱动测试。可以完美和unittest结合实现数据驱动。
- DDT使用的方式(通过装饰器来使用)
在函数或者类上面加上一个装饰器用来实现一些特定的功能。
@ddt 装饰类,作用是用于申明当前类使用ddt数据驱动
@data 装饰函数,作用是给函数传值
@unpack 装饰函数,作用是数据解包
@file_data 装饰函数,作用是直接读取yaml、json文件
Ddt+excel数据驱动代码框架设计思路:
#* 可以分别读取数据,*只能帮我们去除一层括号里的数据,下面的例子是2层括号,第2层括号里有3个数值需要分别读取,就需要unpack,然后添加3个参数,a,b,c
参考网站:https://www.cnblogs.com/JacquelineQA/p/12734946.html
@data(*ExcelUtil().read_excel())
@unpack
#如果改成pytest
#pytest.mark.parametrize(“index,username,password”,ExcelUtil().read_excel())
Def test_01_login(self,index,username,password):
Print(index,username,password)
‘’’登录’’’
Lp = LoginPage(self.driver)
Lp.login_ecshop(username,password)
If index==1:
#断言
Self.assertEqual(lp.get_except_result(),’退出’)
#assert lp.get_except_result()==’退出’
Ale = driver.switch_to.alert
#access:是点击确定,dismiss:点击取消,text: 获得文本,send_keys: 输入值
Ale.accept()
- 读取excel数据文件的程序段
Def get_object_path(self):
Return os.path.abspath(os.path.dirname(__file__)).split(“当前目录名”)[0]
Def read_excel(self):
#openpyx,xlrd
#加载excel工作薄
Wb = openpyxl.load_workbook(self.get_object_path()+”data/login_data.xlsx”)
#获得sheet对象
Sheet = wb[‘login’]
#获得excel的行数和列数
Print(sheet.max_row,sheet.max_column)
#循环
All_ist = []
For rows in range(2,sheet.max_row+1):
Temp_list = []
For cols in range(1,sheet.max_column+1):
Temp_list.append(sheet.cell(rows,cols).value)
All_list.append(temp_list)
Return all_list
Base.py基础层selenium封装的写法
#定位元素的关键字
Def locator_element(self,loc):
Return sef.driver.find_element(*loc)
#设置值的关键字
Def send_keys(self,loc,value):
Self.locator_element(loc).send_keys(value)
#单击的关键字
Def click(self,loc):
Self.locator_element(loc).click()
- 完善达到在企业里面能够实际落地的web自动化测试框架
编辑语音:python/ java
设计模式: POM 关键字驱动模式
用例管理: unittest/ pytest
数据驱动: ddt/pytest.mark.parameters()
二次封装: excel封装,ini/yaml配置文件封装,数据库封装
日志监控:logger日志收集
异常处理:try except
Jenkins: 持续集成,无人值守
Docker: 镜像容器技术
分布式运行:grid
前端代码:html和javascript
进行框架模式分装
好处:
解决:线性脚本的问题
解决:代码不能重复利用的问题
解决:后期的维护问题
分三层:
- 基础层:base 主要放selenium原生的方法
- 页面对象层:po 主要放页面的元素和页面的动作
- 测试用例层:testcase 存放测试用例以及测试数据
页面对象层调用基础层的方法,测试用例层调用页面对象层的方法。
- Unittest断言
Unittest断言用于判断预期结果和实际结果是否相符。一个程序中如果没有断言就是一个没有灵魂的程序。
常用的有以下三个断言方法:
Self.assertEqual(): 判断两个值是否相等
Self.assertTrue(): 判断一个值是否为True
Self.assertIn(): 判断一个值是否在另一个值里面
946






