1、创建Python虚拟环境(Mac):
python -m venv tutorial-env
cd tutorial-env/
source bin/activate 激活虚拟环境
pip list 查看虚拟环境包、库
pip install selenium==3.8.1 安装selenium
deactivate 退出虚拟环境
2、pip介绍
pip是python中的标准库管理器,它允许你安装和管理不属于python标准库的其他软件包;
pip help 帮助
pip install 安装
pip install 包名 == 版本号
pip install -i 镜像地址 --trusted-host 镜像地址对应的host
国内pip源:阿里云:https://mirrors.aliyun.com/pypi/simple
清华: https://pypi.tuna.tsinghua.edu.cn/simple
豆瓣:https://pypi.douban.com/simple
pip install -U 包名 升级包
pip uninstall 卸载
pip list 列出所有的包文件
pip download 下载包
pip search requests 搜索包
3、单元测试概述
单元测试是开发者编写的一小段代码,用于检测被测代码的一个很小的、很明确的功能是否正确;一个单元测试是用于判断某个特定条件(或者场景)下某个特定函数的行为;
需注意:单元测试的时候一个大前提就是需要清楚的知道,自己要测试的程序块所预期的输入和输出,然后根据这个预期和程序逻辑来书写case;这里的语气结果一定要针对需求/设计的逻辑去写,而不是针对程序的实现去写,否则单测就是去了意义。
单元测试框架列举及国内大厂现状:
Unittest:python内置的标准类库,它的API跟Java的JUnit,C++的CppUnit很相似
pytest:丰富、灵活的测试框架,语法简单,可以结合allure生成一个炫酷的测试报告,目前主流
Nose:Nose是对unittest的扩展,使得python的测试更加简单
Mock:unittest.mock是用来测试python的库,这是一个标准库
单元测试覆盖率:
代码覆盖率也被用于自动化测试和手工测试来度量测试是否全面的指标之一,应用覆盖率的思想增可以增强测试用例的设计
被测代码片段demo:
def demo_method(a, b, x):
if (a > 1 and b == 0):
x = x / a
if (a == 2 or x>1):
x = x + 1
return x
单元测试覆盖类型:
语句覆盖:定义:通过设计一定量的测试用例,保证被测试的方法每一行代码都会被执行一遍;运行测试用例的时候被击中的代码行即称为被覆盖的语句;
测试用例:仅需要一条case,即可实现行覆盖;
a = 3, b = 0, x = 4
漏洞:将and ->or 会出问题
行覆盖是一个最基础的覆盖方式,但也是最薄弱的,如果完全依赖行覆盖,会出现很严重的问题
条件覆盖:定义:条件覆盖和判定覆盖类似,不过判定覆盖关注整个判定语句,而条件覆盖则关注某个判断条件
测试用例:if (a >1 and b ==0)
Test Cases | a > 1 | b == 0 |
Case1 | T | T |
Case2 | T | F |
Case3 | F | T |
Case4 | F | F |
缺陷:测试用例指数级增加(2**conditions)
判断覆盖:定义:运行测试用例的过程中被击中的判定语句;
测试用例:
Test Cases | a b x | (a>1)&&(b==0) | a==2||x>1 | ExecutePath |
Case1 | 2 0 3 | T | T | 135 |
Case2 | 1 0 1 | F | F | 124 |
Case3 | 3 0 3 | T | F | 134 |
Case4 | 2 1 1 | F | T | 125 |
漏洞:大部分的判定语句是由多个逻辑条件组合而成,若仅仅判断其整个最终结果,而忽略每个条件的取值情况,必然会遗漏部分测试路径;
例:a==2 or x>1 --> a==2 or x<1
路径覆盖:定义:覆盖所有可能执行的路径
测试用例:
Test Cases | a b x | ExecutePath |
Case1 | 2 0 3 | 135 |
Case2 | 1 0 1 | 124 |
Case3 | 3 0 3 | 134 |
Case4 | 2 1 1 | 125 |
4、unittest编写与规范
Unittest提供了test cases、test suites、test fixtures、test runner相关的组件
编写规范:
测试模块首先 import unittest
测试类必须继承 unittest.TestCase
测试方法必须以‘test_’开头
5、unittest测试框架结构
setUp用来为测试准备环境,tearDown用来清理环境;
如果想要在所有case执行之前准备一次环境,并在所有case执行结束后再清理环境,可以用setUpClass()与tearDownClass();比如:数据库连接及销毁;
如果想有些办法不在本次执行使用 @unittest.skip
测试方法的命名:以test开头
各种执行-单一用例、全部
6、setup与teardown
基于测试方法级别的setUp,tearDown;执行每个测试方法的时候都会执行一次setUp和tearDown
基于类级别的setUpClass,tearDownClass;执行这个类里面的所有测试方法只有一次执行setup,tearDown
7、unittest执行测试用例
编写unittest测试用例的原则:unittest会自动识别以test开头的函数是测试代码,test一定要是小写;
执行测试用例的顺序:测试用例执行顺序是以test后面的字母顺序执行的,例如:test_a,test_b,test_c
多个测试用例的集合就是测试套件,通过测试套件来管理多个测试用例:
执行方法一:unittest.main()
执行方法二:加入容器中执行:
suite = unittest.TestSuite()
suite.addTest(TestMethod('test_01'))
suite.addTest(TestMethod('test_02'))
unittest.TextTestRunner().run(suite)
执行方法三:此用法可以同时测试多个类
suite1 = unittest.TestLoader()loadTestsFromTestCase(TestCase1)
suite2 = unittest.TestLoader().loadTestsFromTestCase(TestCase2)
suite = unittest.TestSuite([suite1,suite2])
unittest.TextTestRunner(verbosity=2).run(suite)
执行方法四:匹配某个目标下所有以test开头的py文件,执行这些文件下的所有测试用例
test_dir = './test_case'
discover = unittest.defaultTestLoader.discover(test_dir,pattern='test_*.py')
discover可以一次调用多个脚本;test_dir被测试脚本的路径;pattern脚本名称匹配规则
测试用例执行过程:
8、pytest介绍
pytest是一个非常成熟的全功能的python测试框架:简单灵活、容易上手;支持参数化;测试用例的skip和xfail,自动失败重试等处理;
能够支持简单的单元测试和复杂的功能测试,还可以用来做selenium/appnium等自动化测试、接口自动化测试(pytest+requests);
pytest具有很多第三方插件,并且可以自定义扩展,比较好用的如pytest-allure(完美html测试报告生成),Pytest-xdist(多CPU分发)等;
可以很好的和jenkins集成;
9、测试用例的识别与运行
测试文件:test_*.py / *_test.py
用例识别:Test*包含的所有test_*的方法(测试类不能带有__init__方法);不在class中的所有的test_*方法;
pytest也可以执行unittest框架写的用例和方法;
终端执行:
pytest/py.test
pytest -v (最高级别信息 --verbose)打印详细运行日志信息
pytest -v -s 文件名.py (s是带控制台输出结果,也是输出详细)
Pytest 文件名.py 执行单独一个pytest模块
pytest 文件名.py::类名 运行某个模块里面某个类
pytest 文件名.py::类名::方法名 运行某个模块里面某个类里面的方法
测试用例常用参数:
pytest -x 文件名 一旦运行到报错,就停止运行
pytest --maxfail=[num] 当运行错误达到num的时候就停止运行
Pytest -k "类名 and not 方法名" 执行某个关键字的用例
pytest -m [标记名] @pytest.mark.[标记名] 将运行有这个标记的测试用例
常用的执行参数:
pytest --collect-only 只收集用例
pytest --junitxml=./result.xml 生成执行结果文件
Pytest --setup-show 回溯fixture的执行过程
10、pytest框架结构
模块级(setup_module/teardown_module)模块始末,全局的(最高)
函数级(setup_funtcion/teardown_function)只对函数用例生效(不在类中)
类级(setup_class/teardown_class)只在类中前后运行一次(在类中)
方法级(setup_method/teardown_methond)开始于方法始末(在类中)
类里面的(setup/teardown)运行在调用方法的前后
11、参数化使用
@pytest.mark.parametrize(argnames, argvalues)
argnames:要参数化的变量,string(逗号分割),list,tuple
argvalues:参数化的值,list , list[tuple]
使用list:
@pytest.mark.parametrize(['a', 'b'], [(10, 20)(10, 30)])
def test_param(self, a, b):
print(a+b)
使用string:
@pytest.mark.parametrize('a, b',[(10, 20)(10, 30)])
def test param(self, a, b):
print(a+b)
使用tuple:
@pytest.mark.parametrize(('a', 'b'),[(10, 20)(10, 30)])
def test param(self, a, b):
print(a+b)
12、yaml实现方式
yaml实现list
list
- 10
- 20
- 30
yaml实现字典
dict
by: id
locator: name
action: click
yaml进行嵌套:
例1:
-
- by: id
- locator: name
- action: click
例2:
companies:
-
id: 1
name: company1
price: 200W
-
id: 2
name: company2
price:500W
例2转换:
加载yaml文件:yaml.safe_load(open('./data.yaml'))
@pytest.mark.parametrize(['a', 'b'], yaml.safe_load(open('./data.yaml')))
def test_param(self, a, b):
print(a+b)
13、驱动
驱动简介:数据驱动就是数据的改变从而驱动自动化测试的执行,最终引起测试结果的改变;简单来说,就是参数化的应用,数据量小的测试用例可以使用代码的参数化来实现数据驱动,数据量大的情况下建议大家使用一种结构化的文件(例如yaml, json等)来对数据进行存储,然后在测试用例中读取这些数据;
应用场景:App、Web、接口自动化测试
测试步骤的数据驱动
测试数据的数据驱动
配置的数据驱动