接到一个项目,在需求分析的阶段,我们需要熟悉的部分包含:
测试计划一般由项目经理制定,主要是时间、技术、进度、优先级的管控,可以确认哪些功能需要引入自动化测试(自动化测试技术python/java)。
测试计划还会涉及到可行性分析,风险分析。
测试用例的编写一般是在excel文档中实现的。
通常来说,任何的一个项目或者是新功能,会先进行手工测试,也是要进行全量的用例编写。
自动化测试主要应用场景:
接口文档形式:
通过抓包,postman调试工具 ,我们知道了怎么设计用例,预期结果。
excel编写,以前程贷注册接口为例。
注意:json数据一定要符合规范,不然转成字典会报错。(引号必须是双引号)
预期结果根据postman运行后得出。
如果领导给你一个自动化测试的计划,
先不要着急做到十全十美,第一步是验证你的自动化测试程序是否能正常运行。
先把功能实现。
写一个单独的自动化测试用例函数。test_开头的测试用例函数,需要有请求发送,得到响应结果,断言。然后生成测试报告。
test_register.py内容如下:
import unittest
import requests
class TestRegister(unittest.TestCase):
def test_register_1(self):
# 1.准备测试数据
url = 'http://api.lemonban.com:8766/futureloan/member/register'
method = 'post'
headers = {"X-Lemonban-Media-Type": "lemonban.v2"}
json_data = {"mobile_phone": "", "pwd": "12345678"}
expected = {
"code": 1,
"msg": "手机号为空",
"data": None,
"copyright": "Copyright 柠檬班 © 2017-2020 湖南省零檬信息技术有限公司 All Rights Reserved"
}
# 2.发送接口请求,得到实际结果
resp = requests.request(method=method, url=url, headers=headers, json=json_data)
actual = resp.json()
# 3.预期结果个实际结果的断言
self.assertEqual(expected, actual)
run.py用于生成测试报告:
import unittest
import unittestreport
# 收集用例,tests用例所在的包
suite = unittest.defaultTestLoader.discover('tests')
# 运行用例
# runner = unittest.TextTestRunner()
# runner.run(suite)
# 生成测试报告
runner = unittestreport.TestRunner(suite, tester='困困')
runner.run()
运行结果:
有了以上的基础后,我们可以引入ddt,优化下测试用例函数,降低代码重复率。
ddt适用的场景:不同的数据,测试步骤是一样的。
test_register_ddt.py:
import unittest
import requests
import json
from common.excel import read_excel
from common.logger import my_log
from ddt import ddt, data
from setting.config import config_file, host
# 得到测试数据
excel_data = read_excel(file=config_file, sheet_name='register')
@ddt
class TestLogin(unittest.TestCase):
@data(*excel_data)
def test_login(self, info):
# TODO:域名和端口,环境和变化的是否更方便的修改,不需要放在excel中,可以放在配置文件config.py
my_log.info(f'测试用例{info}正在执行。。。')
url = host + info['url']
method = info['method']
# 反序列化,将json格式字符串转化成python字典,因为requests.request的参数需要字典格式
json_data = json.loads(info['json'])
headers = json.loads(info['headers'])
expected = json.loads(info['expected'])
resp = requests.request(method=method, url=url, headers=headers, json=json_data)
actual = resp.json()
self.assertEqual(expected, actual)
tests/:存储自动化用例
common/:通用模块
logs/:保存日志文件
data/:保存测试数据,excel文件
setting/:配置文件
reports/:保存测试报告
run.py:收集用例,运行用例,生成测试报告
目前整个框架已经实现了流程的正常运行,但还有几个问题需要优化下。
6.1 生成测试报告,每次都是生成report.html,每次生成都会覆盖,那有没有办法每次都生成新的报告,不覆盖呢?解决方式报告名称添加时间戳。
import unittest
import unittestreport
from datetime import datetime
# 收集用例,tests用例所在的包
suite = unittest.defaultTestLoader.discover('tests')
# 生成测试报告
# 获取时间戳,now()获取现在的时间,strftime()转化成字符串
report_time = datetime.now().strftime("%Y%m%d%H%M%S")
# 字符串拼接
filename = f'report-{report_time}.html'
runner = unittestreport.TestRunner(suite, tester='困困', filename=filename)
runner.run()
运行结果:
6.2 手机号注册成功后,如果再次运行用例,该条用例一定会失败,那怎么避免手机号码重复的问题呢?
方案1:手工+1,可能与其他人已注册的号码冲突,也可能运营商不支持此号码段。
方案2:数据库清掉。不建议删数据,然后也不一定有删除的权限。
方案3:参数动态化,手机号随机生成,excel中使用标记(注册成功的用例记录)。
手机号随机生成,可以使用第三方库faker实现,使用前先安装:pip install faker
伪造手机号函数存放在common文件夹下,
helper.py:
from faker import Faker
def generate_mobile():
faker = Faker(locale=['zh-cn'])
# 生成伪造手机号码
return faker.phone_number()
test_register_ddt.py:
import unittest
import requests
import json
from common.excel import read_excel
from common.logger import my_log
from common.helper import generate_mobile
from ddt import ddt, data
from setting.config import config_file, host
# 得到测试数据
excel_data = read_excel(file=config_file, sheet_name='register')
@ddt
class TestLogin(unittest.TestCase):
@data(*excel_data)
def test_login(self, info):
# TODO:域名和端口,环境和变化的是否更方便的修改,不需要放在excel中,可以放在配置文件config.py
my_log.info(f'测试用例{info}正在执行。。。')
url = host + info['url']
method = info['method']
# 反序列化,将json格式字符串转化成python字典,因为requests.request的参数需要字典格式
json_data = info['json']
# 检测:如果json_data中存在某个标记,就说明需要自动生成一个手机号码
# 直接调用函数generate_mobile
# json_data = 替换完成新的手机号之后的字符串
if '#mobile_phone#' in json_data:
mobile = generate_mobile()
json_data = json_data.replace('#mobile_phone#',mobile)
json_data = json.loads(json_data)
headers = json.loads(info['headers'])
expected = json.loads(info['expected'])
resp = requests.request(method=method, url=url, headers=headers, json=json_data)
actual = resp.json()
self.assertEqual(expected, actual)
运行结果:
从运行结果中可以看出来,虽然手机号实现动态获取且随机了,但运行用例还是失败了,因为预期结果和实际结果中有些字段的值是动态的且没有必要进行比较的,比如data,copyright。
6.3 全量断言和部分断言
-全量断言:一个字都不能差,麻烦
-部分断言,提取有用的关键字段进行断言,code,msg。实战当中基本使用部分断言。
修改excel中expected的值:
修改代码:
# 简单版本 部分断言
self.assertEqual(expected['msg'], actual['msg'])
# 多个字段需要校验,对expected进行for循环
for key, value in expected.items():
self.assertEqual(value, actual[key])
# 笨方法,多个字段分别断言
self.assertEqual(expected['msg'], actual['msg'])
self.assertEqual(expected['code'], actual['code'])
test_register_ddt.py:
import unittest
import requests
import json
from common.excel import read_excel
from common.logger import my_log
from common.helper import generate_mobile
from ddt import ddt, data
from setting.config import config_file, host
# 得到测试数据
excel_data = read_excel(file=config_file, sheet_name='register')
@ddt
class TestLogin(unittest.TestCase):
@data(*excel_data)
def test_login(self, info):
# TODO:域名和端口,环境和变化的是否更方便的修改,不需要放在excel中,可以放在配置文件config.py
my_log.info(f'测试用例{info}正在执行。。。')
url = host + info['url']
method = info['method']
# 反序列化,将json格式字符串转化成python字典,因为requests.request的参数需要字典格式
json_data = info['json']
# 检测:如果json_data中存在某个标记,就说明需要自动生成一个手机号码
# 直接调用函数generate_mobile
# json_data = 替换完成新的手机号之后的字符串
if '#mobile_phone#' in json_data:
mobile = generate_mobile()
json_data = json_data.replace('#mobile_phone#', mobile)
json_data = json.loads(json_data)
headers = json.loads(info['headers'])
expected = json.loads(info['expected'])
resp = requests.request(method=method, url=url, headers=headers, json=json_data)
actual = resp.json()
# 简单版本 部分断言
# self.assertEqual(expected['msg'], actual['msg'])
# 多个字段需要校验,对expected进行for循环
for key, value in expected.items():
self.assertEqual(value, actual[key])
# 笨方法,多个字段分别断言
# self.assertEqual(expected['msg'], actual['msg'])
# self.assertEqual(expected['code'], actual['code'])
运行结果:
7.1测试金字塔
从下往上:单元测试->服务(接口)测试->UI用户界面测试->系统测试(手工测试)
左侧代表:速度
右侧代表:成本
7.2 什么样的项目适合做自动化测试
7.3 图片验证码
测试接口时,遇到图片验证码的问题,该怎么解决?
7.4 第三方伪造库:faker
from faker import Faker
# zh-cn指定中国地区
faker = Faker(locale=['zh-cn'])
# 生成伪造手机号码
print(faker.phone_number())
# 伪造电商地址
print(faker.address())
# 伪造公司
print(faker.company())
# 伪造姓名
print(faker.name())
# 伪造身份证号
print(faker.ssn())
运行结果:
7.5 debug
在编写代码过程中,调试很重要:
首先程序报错: