pytest官方文档:https://docs.pytest.org/en/stable/getting-started.html pytest是一个非常流行且高效的Python测试框架,它提供了丰富的功能和灵活的用法,使得编写和运行测试用例变得简单而高效。 pytest的特点:
pip install pytest==8.3.2pytest 版本 | 最低 Python 版本 |
|---|---|
8.0+ | 3.8+ |
7.1+ | 3.7+ |
6.2 - 7.0 | 3.6+ |
5.0 - 6.1 | 3.5+ |
3.3 - 4.6 | 2.7, 3.4+ |
安装好pytest后,确认pycharm中python解释器已经更新,来看一下有pytest框架和没有 pytest框架编写代码的区别:

两张对比图可以明显看出来,未安装pytest框架的情况下需要编写main函数,在main函数中手动 调用测试用例testo1;安装了pytest框架后方法名前有直接运行标志。
当满足以上要求后,可通过命令行参数pytest直接运行符合条件的用例

#测试类必须以Test开头,并且不能有__init__方法。
class Test03 :
def __init__(self):
print("-----init-------")
def test_03_01(self) :
print("test_03_01")
def test_03_02(self) :
print("test_03_02")
def test_03_03(self) :
print("test_03_03")
由于pytest的测试收集机制,测试类中不可以定义__init__方法。pytest采用自动发现机制来收集测试用例。它会自动实例化测试类并调用其所有以test结尾的方法作为测试用例。如果测试类中定义了_init__方法,那么当pytest实例化该类时,_init__方法会被调用,这可能会掩盖测试类的实际测试逻辑,并引入额外的副作用,影响测试结果的准确性。
#测试方法以test开头
def test_02_01() :
print("test_02_01")
pytest提供了丰富的命令行选项来控制测试的执行。以下是一些常用的pytest命令行参数及其使用说明。
命令 | 描述 | 备注 |
|---|---|---|
pytest | 在当前目录及其子目录中搜索并运行测试。 | |
pytest -v | 增加输出的详细程度。 | |
pytest -s | 显示测试中的 print 语句。 | |
pytest test_module.py | 运行指定的测试模块。 | |
pytest test_dir/ | 运行指定目录下的所有测试。 | |
pytest -k <keyword> | 只运行测试名包含指定关键字的测试。 | |
pytest -m <marker> | 只运行标记为指定标记的测试。 | |
pytest -q | 减少输出的详细程度。 | |
pytest --html=report.html | 生成 HTML 格式的测试报告。 | 需要安装 pytest-html 插件 |
pytest --cov | 测量测试覆盖率 | 需要安装 pytest-cov 插件 |
pytest -s -v 或者 pytest -sv (可以连写)


#指定⽂件:pytest 包名/⽂件名
pytest cases/test_01.py
#指定测试⽤例: pytest 包名/⽂件名::类名::⽅法名
pytest cases/test_02.py::Test::test_adef test_01_01() :
print("cases -> test_01_01")
def test_01_02() :
print("cases -> est_01_02")
def test_01_03() :
print("cases -> test_01_03")class Test02:
def test_02_01(self):
print("cases ->test_02_01")
def test_02_02(self):
print("cases ->test_02_02")
def test_02_03(self):
print("cases ->test_02_03")

当我们既要详细输出,又要指定文件时,命令会又臭又长,而且每次运行都需要手动输入命 令,如何解决? 将需要的相关配置参数统一放到pytest配置文件中。
参数 | 解释 |
|---|---|
addopts | 指定在命令行中默认包含的选项。 |
testpaths | 指定搜索测试的目录。 |
python_files | 指定发现测试模块时使用的文件匹配模式。 |
python_classes | 指定发现测试类时使用的类名前缀或模式。 |
python_functions | 指定发现测试函数和方法时使用的函数名前缀或模式。 |
norecursedirs | 指定在搜索测试时应该避免递归进入的目录模式。 |
markers | 定义测试标记,用于标记测试用例。 |
[pytest]
addopts = -vs
testpaths = ./cases
python_files = test_*.py
python_classes = Test*配置好pytest.ini文件后,命令行执行pytest命令即可,无需再额外指定其他参数 pytest.ini文件通常位于项目的根目录下。通过在pytest.ini中定义配置项,可以覆盖 pytest的默认行为,以满足项目的需求。
使用pytest框架,测试类中不可以添加init()方法,如何进行数据的初始化? 在测试框架中,前后置是指在执行测试用例前和测试用例后执行一些额外的操作,这些操作可以用于设置测试环境、准备测试数据等,以确保测试的可靠性 pytest框架提供三种方法做前后置的操作:
class Test02:
def setup_method(self) :
print("setup_method")
def test_02_01(self):
print("cases ->test_02_01")
def test_02_02(self):
print("cases ->test_02_02")
def teardown_method(self) :
print("teardown_method")
class Test02:
def setup_class(self) :
print("setup_class")
def test_02_01(self):
print("cases ->test_02_01")
def test_02_02(self):
print("cases ->test_02_02")
def teardown_class(self) :
print("teardown_class")
断言(assert)是一种调试辅助工具,用于检查程序的状态是否符合预期。如果断言失(即条件为假),Python解释器将抛出一个AssertionError异常。断言通常用于检测程序中的逻辑错误。 pytest允许你在 Python测试中使用标准的 Pythonassert语句来验证预期和值。
assert 条件, 错误信息免费学习API资源:http://jsonplaceholder.typicode.com/
def test_03_01():
a = 1
b = 2
assert a == b
def test_03_01():
str1 = "hello"
str2 = "hallo"
assert str1 == str2
def test_03_01():
# 断言列表
expect_list = [1, 'apple', 3.14]
actual_list = [1, 'apple', 3.14]
assert expect_list == actual_list
# 断言元组
expect_tuple = (1, 'apple', 3.14)
actual_tuple = (1, 'apple', 3.14)
assert expect_tuple == actual_tuple
# 断言字典
expect_dict = {'name': 'Alice', 'age': 25}
actual_dict = {'name': 'Alice', 'age': 25}
assert expect_dict == actual_dict
# 断⾔集合
expect_set = {1, 2, 3, 'apple'}
actual_set = {1, 2, 3, 'apple'}
assert expect_set == actual_setdef divide(a, b):
assert b != 0, "除数不能为0"
return a / b
def test_03_01():
# 正常情况
print(divide(10, 2)) # 输出 5.0
# 触发断⾔
print(divide(10, 0)) # 抛出 AssertionError: 除数不能为0
#断言接口返回值完整字段和值
def test():
url = "http://jsonplaceholder.typicode.com/posts/1"
r = requests.get(url=url)
expect_data = {
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}
actual_data = r.json()
assert expect_data == actual_data
# 断言接口返回值重要字段
def test2():
url = "http://jsonplaceholder.typicode.com/comments?postId=1"
r = requests.get(url=url)
print(r.json())
assert r.json()[0]['id'] == 1
#断言接口html返回值
def test3():
url = "http://jsonplaceholder.typicode.com/"
r = requests.get(url=url)
assert "Use your own data" in r.text
参数化设计是自动化设计中的一个重要组成部分,它通过定义设计参数和规则,使得设计过程更加灵活和可控。 pytest中内置的pytest.mark.parametrize装饰器允许对测试函数的参数进行参数化。
# 参数为同一类型
@pytest.mark.parametrize("data",(1,2,3))
def test(data):
print(data)
# 参数不是同一类型
@pytest.mark.parametrize("data",(1,"a",33.3))
def test2(data):
print(data)
# 多组参数实现参数化
@pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2+4", 6),("6*9", 42)])
def test_eval(test_input, expected):
assert eval(test_input) == expected
@pytest.mark.parametrize("n,expected", [(1, 2), (3, 4)])
class TestClass:
def test_simple_case(self, n, expected):
assert n + 1 == expected
def test_weird_simple_case(self, n, expected):
assert (n * 1) + 1 == expected
pytestmark = pytest.mark.parametrize("data",(1,2))
class Test_A:
def test_a01(self, data):
print(data)
def test_a02(self, data):
print("data")
class Test_B:
def test_b01(self, data):
print(data)
def test_b02(self, data):
print("data")
def data_provider():
return ["a", "b","c" ]
# 定义⼀个测试函数,它依赖于上⾯函数的返回值
@pytest.mark.parametrize("data", data_provider())
def test_data(data):
assert data != None
print(f"Testing with data provider: {data}")
def fixture_01():
print("fixture_01")
def test_01():
fixture_01()
print("test_01")
import pytest
@pytest.fixture
def fixture_01():
print("fixture_01")
def test_01(fixture_01):
print("test_01")
未标记fixture方法的调用与fixture标记的方法调用完全不一样,前者需要在方法体中调用, 而后者可以将函数名作为参数进行调用。
测试脚本中存在的很多重复的代码、公共的数据对象时,使用 fixture 最为合适
import pytest
@pytest.fixture
def login():
print("---执⾏登陆操作-----")
def test_list(login):
print("---访问列表⻚")
def test_detail(login):
print("---访问详情⻚")
@pytest.fixture
def first_entry() :
return "a"
@pytest.fixture
def order(first_entry) :
return [first_entry]
def test_string(order) :
order.append("b")
assert order == ["a", "b"]
class Fruit :
def __init__(self, name, color) :
self.name = name
self.color = color
def __eq__(self, other):
#根据颜色判断
return self.color == other.color
@pytest.fixture
def my_fruit() :
return Fruit("apple", "red")
@pytest.fixture
def your_fruit() :
return [Fruit("banana","yellow"),Fruit("apple","green")]
def test_fruit(my_fruit, your_fruit) :
assert my_fruit in your_fruit当我们运行测试时,我们希望确保它们能够自我清理,以便它们不会干扰其他测试(同时也避免留下大量测试数据来膨胀系统)。pytest中的fixture提供了一个非常有用拆卸系统,它允许我们为每个fixture定义具体的清理步骤。 “Yield”fixture使用yield而不是return。有了这些fixture,我们可以运行一些代码,并将对象返回给请求的fixture/test,就像其他fixture一样。唯一的不同是:
执行顺序:一旦pytest确定了fixture的线性顺序,它将运行每个fixture直到它返回或yield,然后继续执行列表中的下一个fixture做同样的事情。 测试完成后,pytest将逆向遍历fixture列表,对于每个yield的fixture,运行yield语句之后的代码。
@pytest.fixture
def operator():
print("数据的初始化")
yield 100
print("数据的清理")
def test_operator(operator):
print(100 + operator)
assert 100 == operator
@pytest.fixture
def open_close():
print("前置操作,初始化.....")
yield
print("后置操作,清理数据.....")
def test_01(open_close):
print("第⼀个测试⽤例")
@pytest.fixture
def file_read() :
print("打开文件句柄")
f = open("test.txt","r",encoding="utf-8")
yield f
print("关闭文件句柄")
f.close()
def test_file(file_read) :
r = file_read
str = r.read()
print(str)
@pytest.fixture
def file_read() :
print("打开文件句柄")
f = open("test.txt","r",encoding="utf-8")
yield f
print("关闭文件句柄")
f.close()
@pytest.fixture
def file_write():
print("打开文件句柄")
f = open("test.txt","w",encoding="utf-8")
return f
def test_file(file_read,file_write) :
# 写⼊数据
w = file_write
w.write("测试数据")
w.close() # 写⼊后关闭⽂件句柄,以便读取
r = file_read
str = r.read()
print(str)
pytest.fixture(scope='', params='', autouse='', ids='', name='')import pytest
@pytest.fixture(scope="function")
def fixture_01() :
print("初始化")
yield
print("清理")
class TestCase() :
def test_01(self, fixture_01) :
print("第一个测试用例")
def test_02(self, fixture_01) :
print("第二个测试用例")
import pytest
@pytest.fixture(scope="class")
def fixture_01() :
print("初始化")
yield
print("清理")
class TestCase() :
def test_01(self, fixture_01) :
print("第一个测试用例")
def test_02(self, fixture_01) :
print("第二个测试用例")
结论:
规则:
#conftest.py
import pytest
@pytest.fixture(scope="module", autouse=True)
def fixture_01():
print("初始化")
yield
print("清理")def test_case01():
print("单独放出来的测试⽤例01")
class TestCase01():
def test_01(self):
print("第⼀个测试用例")
def test_02(self):
print("第二个测试用例")
def test_case02():
print("单独放出来的测试⽤例01")
class TestCase02():
def test_01(self):
print("第⼀个测试用例")
def test_02(self):
print("第二个测试用例")
import pytest
@pytest.fixture(scope="session", autouse=True)
def fixture_01():
print("初始化")
yield
print("清理")
import pytest
@pytest.fixture(scope="class", autouse=True)
def fixture_01() :
print("初始化")
yield
print("清理")
class Test_case():
def test_01(self):
print("第一个测试用例")
def test_02(self):
print("第二个测试用例")
为False时:

autouse默认为False,即当前的fixture需要手动显示调用,在该案例之前我们默认使用的 都是autouse=False 当autouse=True时,fixture会在所有测试函数执行之前自动调用,无论这些测试函数是否显 式地引用了该fixture
# 定义⼀个参数化的 fixture
import pytest
@pytest.fixture(params=["a", "b"])
def data_provider(request):
return request.param
# 定义⼀个测试函数,它依赖于上⾯的参数化 fixture
def test_data(data_provider):
assert data_provider != None
print(f"Testing with data provider: {data_provider}")
#yml文件
key: value#JSON文件
{
"key": "value"
}
int_key: 123
float_key: 123.456{
"int_key": 123,
"float_key": 123.456
}
bool_key: true{
"bool_key": true
}
string_key: "This is a string"{
"string_key": "This is a string"
}
list_key:
- item1
- item2
- item3{
"list_key": ["item1", "item2", "item3"]
}
map_key:
sub_key1: sub_value1
sub_key2: sub_value2
nested_key:
list_key:
- item1
- item2
map_key:
sub_key1: sub_value1
sub_key2: sub_value2{
"nested_key": {
"list_key": [
"item1",
"item2"
],
"map_key": {
"sub_key1": "sub_value1",
"sub_key2": "sub_value2"
}
}
}
yaml文件通常作为配置文件来使用,可以使用yaml库来读取和写入YAML文件
pip install PyYAML==6.0.1
#往yaml中写入数据
import yaml
def write_yaml(filename, data):
with open(file = filename, mode = 'a+', encoding = "utf-8") as f:
# 写入数据
yaml.safe_dump(data=data, stream=f)
# 测试往yaml文件中写入数据
def test_write() :
data = {
"name" : "zhangsan",
"age" : 22,
}
write_yaml("firstyaml.yml", data)
# 读取yaml文件中的数据
def read_yaml(filename):
with open(file = filename, mode = 'r', encoding = "utf-8") as f:
data = yaml.safe_load(stream = f)
return data
#测试读取yaml中的数据
def test_read() :
data = read_yaml("firstyaml.yml")
print(data)
注意:
Python的内置类型字典和json格式非常像
因此当我们想要转为JSON时,就必须将Python中的字典格式数据转为JSON格式
def test_read() :
data = read_yaml("firstyaml.yml")
json_str = json.dumps(data)
print(json_str)
# 清空 yaml 文件中的数据
def clear_yaml(filename):
with open(file = filename, mode = 'w', encoding = "utf-8") as f:
f.truncate()
# 测试清空 yaml 文件中的数据
def test_clear() :
clear_yaml("firstyaml.yml")JSON Schema一个用来定义和校验JSON的web规范,简而言之,JSON Schema是用来校验json是否符合预期。 根据json创建JSONSchema后,你可以使用你选择的语言中的验证器将示例数据与你的模式进行 验证。
#JSON
{
"code": "SUCCESS",
"errMsg": "",
"data": false
}#schema
{
"type": "object",
"required": [],
"properties": {
"code": {
"type": "string"
},
"errMsg": {
"type": "string"
},
"data": {
"type": "string"
}
}
}json转JSON Schema太麻烦?使用现有工具自动转换:https://tooltt.com/json2schema/ 注意:工具不是万能的,结果可能存在错误,要对自动生成的结果进行二次检查
def test_02():
url = "http://62.234.142.221:58080/board/topList"
header = {
"cookie" : "JSESSIONID=C8DD82EC03C9C3ABCC8D1C930FBD3C47"
}
r = requests.get(url,headers = header)
json_schema = {
"type": "object", # 响应根节点是对象
"required": ["code", "message", "data"], # 建议加上必选字段(根据接口实际返回调整)
"properties": {
"code": {"type": "number"},
"message": {"type": "string"}, # 注意:接口返回的message通常是字符串(比如"success"),之前写number可能报错,这里修正
"data": {
"type": "array", # data是数组
"items": { # 数组中的每个元素是对象
"type": "object",
"properties": {
"id": {"type": "number"},
"name": {"type": "string"},
"articleCount": {"type": "number"},
"sort": {"type": "number"},
"state": {"type": "number"},
"deleteState": {"type": "number"},
"createTime": {"type": "string"},
"updateTime": {"type": "string"}
}
}
}
}
}
validate(r.json(), json_schema)
validate(json, json_schema)是用于验证 JSON 数据是否符合指定 JSON Schema 规则
code、message、data的接口响应数据(code为数字 0,state和deleteState为数字 0 等)。code、state、deleteState被错误定义为string类型)。
required:仅用于 type: "object" 中,指定对象必须包含的属性
type 关键字指定了数据类型。 可以验证 JSON 数据中每个属性的数据类型是否符合预期。常用的数据类型包括:
type | 解释 |
|---|---|
string | 字符串类型,用于文本数据。 |
number | 数字类型,用于表示浮点数。 |
integer | 整数类型,用于表示整数。 |
boolean | 布尔类型,值为 true 或 false。 |
object | 对象类型,用于嵌套的 JSON 对象。 |
array | 数组类型,用于列表或集合。 |
null | 空值类型。 |
int只能表示整形数据,但是 number 表示数字:整数、浮点数...
def test_03():
json = {
"name":"zhangsan",
"height":178.5,
"female":False,
"hobby":{
"aaa":"aaa",
"bbb":"bbb",
}
}
json_schema = {
"type": "object",
"required": [],
"properties": {
"name": {"type": "string"},
"height": {"type": "number"},
"female": {"type": "boolean"},
"hobby":{
"type": "object",
"properties": {
"aaa": {"type": "string"},
"bbb": {"type": "string"},
}
}
}
}
validate(json, json_schema)
"properties"是用于定义 “对象类型("type": "object")” 内部所包含的属性(字段)及其验证规则的关键字
def test_04():
json = {
"data":[
{
"name":"zhangsan",
"age":20
},
{
"name":"lisi",
"age":18
}
],
"addr":None
}
json_schema = {
"type": "object",
"properties": {
"addr": {"type": "null"},
},
"data":{
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "number"},
}
}
}
}
validate(json, json_schema)
items:仅用于type: "array"中,定义数组内元素的验证规则(所有元素需符合同一规则)。
def test_05():
json = {
"name":"zhangsan",
"age":10
}
json_schema= {
"type": "object",
"required": [],
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "number",
# "minimum":0,
# "maximum":100
"exclusiveMinimum":0,
"exclusiveMaximum":100
}
}
}
validate(instance=json,schema=json_schema)pattern:使用正则表达式来验证字符串是否符合特定的模式。 正则表达式在线测试工具:https://www.sojson.com/regex/check.html
代码 | 说明 |
|---|---|
. | 匹配除换行符以外的任意字符 |
\w | 匹配字母或数字或下划线 |
\s | 匹配任意的空白符 |
\d | 匹配数字 |
\b | 匹配单词的开始或结束 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
代码/语法 | 说明 |
|---|---|
* | 重复零次或更多次 |
| 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
def test_06():
json = {
"name": "zhangsa",
"age": 10
}
json_schema = {
"type": "object",
"required": [],
"properties": {
"name": {
"type": "string",
"pattern":"\S{20,}"
},
"age": {
"type": "number"
}
}
}
validate(instance=json,schema=json_schema)\S表示 “非空白字符”(即不能是空格、换行等),{20,}表示 “至少 20 个字符”。因此,"name"字段的值必须是长度≥20 的非空白字符串,所以此时会报错
def test_07():
json = {
"data":[1,2,3,5,5],
"str":"hello"
}
json_schema = {
"type": "object",
"required": [],
"properties": {
"data": {
"type": "array",
# 针对数组添加最大和最小长度限制
"minItems":1,
"maxItems":5,
# 要求数组中元素唯一
"uniqueItems":True,
"items": {
"type": "number"
}
},
"str": {
"type": "string"
}
}
}
validate(instance=json,schema=json_schema)
def test_08():
json = {
"code": "SUCCESS",
"errMsg": "",
# 额外属性
"ccc":"ddd",
"data": [
{
"id": 21430,
"title": "自动化测试实例",
"content": "##在这里写下一篇博客",
"userId": 2,
"deleteFlag": 0,
"createTime": "2025-11-19 21:59",
"updateTime": "2025-11-19T13:59:10.000+00:00",
"loginUser": False,
# 额外字段
"aaa":"aaa",
"bbb":"bbb"
}
]
}
json_schema ={
"type": "object",
# 不允许存在额外属性
"additionalProperties": False,
# 指定对象的最大最小属性数量
"minProperties": 3,
"maxProperties": 3,
# 添加必需属性
"required": [],
"properties": {
"code": {
"type": "string"
},
"errMsg": {
"type": "string"
},
"data": {
"type": "array",
"minProperties": 3,
"maxProperties": 9,
"items": {
"type": "object",
# 不允许存在额外属性
"additionalProperties": False,
"required": ["id","loginUser"],
"properties": {
"id": {
"type": "number"
},
"title": {
"type": "string"
},
"content": {
"type": "string"
},
"userId": {
"type": "number"
},
"deleteFlag": {
"type": "number"
},
"createTime": {
"type": "string"
},
"updateTime": {
"type": "string"
},
"loginUser": {
"type": "boolean"
}
}
}
}
}
}
validate(instance=json,schema=json_schema)

通过required关键字,JSONSchema可以指定哪些属性是必需的。如果JSON实例中缺少这些必需属性,验证将失败。
json_schema ={
"type": "object",
# 不允许存在额外属性
"additionalProperties": False,
# 指定对象的最大最小属性数量
"minProperties": 3,
"maxProperties": 3,
"properties": {
"code": {
"type": "string"
},
"errMsg": {
"type": "string"
},
"data": {
"type": "array",
"required": ["id"],
"minProperties": 3,
"maxProperties": 9,
"items": {
"type": "object",
# 不允许存在额外属性
"additionalProperties": False,
# 添加必需属性
# "required": ["id","loginUser"],
"required": ["id"],
"properties": {
"id": {
"type": "number"
},
"title": {
"type": "string"
},
"content": {
"type": "string"
},
"userId": {
"type": "number"
},
"deleteFlag": {
"type": "number"
},
"createTime": {
"type": "string"
},
"updateTime": {
"type": "string"
},
"loginUser": {
"type": "boolean"
}
}
}
}
}
}

dependentRequired可以定义属性之间的依赖关系。例如,如果某个属性存在,则必须存在另一个属性。
def test_09():
json = {
"username":"zhangsan",
"age":20,
"height":178,
"gender":"male",
"hobby":{
"aaa":"aaa",
#"bbb":"bbb"
}
}
json_schema = {
"type": "object",
"required": [],
"properties": {
"username": {
"type": "string"
},
"age": {
"type": "number"
},
"height": {
"type": "number"
},
"gender": {
"type": "string"
},
"hobby":{
"type":"object",
"properties":{
"aaa":{
"type":"string"
},
"bbb":{
"type": "string"
}
},
"dependentRequired":{
"aaa":["bbb"]
}
}
},
"dependentRequired":{
"age":["height","gender"]
}
}
validate(instance=json,schema=json_schema)
logging是Python标准库中的一个模块,它提供了灵活的日志记录功能。通过logging,开发 者可以方便地将日志信息输出到控制台、文件、网络等多种目标,同时支持不同级别的日志记录,以满足不同场景下的需求。
import logging
# 指定输出级别,输出 info 及以上级别的日志
logging.basicConfig(level=logging.INFO)
# 默认情况下 logging 输出 warning 及以上级别的日志
logging.debug("this is a debug message")
logging.info("this is a info message")
logging.warning("this is a warning message")
logging.error("this is a error message")
logging.critical("this is a critical message")
logger = logging.getLogger("my_logger")
#给 logger 配置自己的日志级别
logger.setLevel(logging.DEBUG)
logger.debug("this is a debug message")
logger.info("this is a info message")
logger.warning("this is a warning message")
logger.error("this is a error message")
logger.critical("this is a critical message")
logger = logging.getLogger("my_logger")
#给 logger 配置自己的日志级别
logger.setLevel(logging.DEBUG)
# 创建文件处理器 -- 将日志输出到 mylog.log 里(可以自动创建)
handler = logging.FileHandler(filename="mylog.log")
# 将处理器添加到日志记录器中
logger.addHandler(handler)
logger.debug("this is a debug message")
logger.info("this is a info message")
logger.warning("this is a warning message")
logger.error("this is a error message")
logger.critical("this is a critical message")
logger = logging.getLogger("my_logger")
#给 logger 配置自己的日志级别
logger.setLevel(logging.DEBUG)
# 创建文件处理器 -- 将日志输出到 mylog.log 里(可以自动创建)
handler = logging.FileHandler(filename="mylog.log")
# 创建一个日志格式器对象
formatter = logging.Formatter(
"%(asctime)s %(levelname)s [%(name)s] [%(filename)s (%(funcName)s:%(lineno)d)] - %(message)s"
)
# 将格式器设置到处理器上
handler.setFormatter(formatter)
# 将处理器添加到日志记录器中
logger.addHandler(handler)
logger.debug("this is a debug message")
logger.info("this is a info message")
logger.warning("this is a warning message")
logger.error("this is a error message")
logger.critical("this is a critical message")
logging.Formatter是用于定义日志输出格式的类。在构造函数中,传递了一个格式字符串,用于指定日志信息的格式。格式字符串中使用了一些特殊的占位符(以开头),这些占位符会被替换为相应的日志信息内容
格式占位符 | 说明 |
|---|---|
%(asctime)s | 日志记录的时间戳,通常显示为日期和时间。 |
%(levelname)s | 日志级别(如 DEBUG、INFO、WARNING、ERROR、CRITICAL)。 |
%(name)s | 日志记录器的名称,通常为模块名称。 |
%(filename)s | 日志记录发生的文件名。 |
%(funcName)s | 日志记录发生的函数名。 |
%(lineno)d | 日志记录发生的行号。 |
%(message)s | 日志消息本身。 |
handler.setFormatter(formatter)将创建的格式器对象设置到处理器上。这意味着处理器在处理日志信息时,会使用这个格式器来格式化日志信息。 通过这种方式,你可以控制日志信息的输出格式,使其包含你感兴趣的信息,如时间戳、日志级别、文件名、函数名、行号等。
官方文档:https://allurereport.org/docs/pytest-configuration
AllureReport由一个框架适配器和allure命令行工具组成,是一个流行的开源工具,用于可视化 测试运行的结果。它可以以很少甚至零配置的方式添加到您的测试工作流中。它生成的报告可以在任何地方打开,并且任何人都可以阅读,无需深厚的技术知识。
下载allure-pytest包
pip install allure-pytest==2.13.5下载 Windows 版 Allure 报告 https://github.com/allure-framework/allure2/releases/download/2.30.0/allure2.30.0.zip
2.1解压后添加系统环境变量(将 allure-2.29.0 对应 bin 目录添加到系统环境变量中)


若出现cmd中执行allure--version可以打印版本,但是pycharm控制台执行命令提 示命题找不到,则需要修改pycharm中命令行环境,如下:

保存后需要重启pycharm!!!!!! 如果还不行则重启大法
1.运行自动化,并指定测试报告放置路径
#allure-results(保存测试报告的路径)
pytest --alluredir=allure-results

2. 查看测试报告
法一:启动⼀个本地服务器来在浏览器中展示测试报告 终端执行命令: allure serve [options] <allure-result>,自动在浏览器打开测试 报告
#不指定端口号和主机地址
allure serve .\allure-results\
#指定端口号
allure serve --port 8787 .\allure-results\
#清除上一次生成的测试报告
allure serve .\allure-results\ --clean-alluredir

法二:从测试结果生成测试报告
终端执行命令:alluregenerate[options]<allure-results>-o <reports>
allure generate .\allure-results\ -o .\allure-report --clean