学习python(基于java基础)

一、数据类型

1.1 整数(int)

Python 的整数没有大小上限,随便写多大都能存、能计算,不会溢出。

python 复制代码
# Python直接算1后面1000个0,Java必须用BigInteger写一堆代码
big_num = 10 ** 1000  
print(big_num)

1.2 浮点数(float)

Python 的 float 等价 Java 的 double(64 位双精度),浮点数有精度损失,建议使用 decimal 模块进行精确计算。

python 复制代码
from decimal import Decimal
# 测试decimal模块
a = Decimal('1.23')
b = Decimal('4.56')
print(a + b)  # 输出: 5.79

1.3 字符串(str)

字符串可以进行拼接和重复操作。

python 复制代码
# 字符串拼接
s1 = 'hello'
s2 = 'world'
print(s1 + s2)  # 输出: helloworld

# 字符串重复
s = 'hello'
print(s * 3)  # 输出: hellohellohello

1.4 布尔值(bool)

bool 继承自 int,True = 1,False = 0,可以直接参与运算。

python 复制代码
print(True + 1)   # 输出: 2
print(False * 5)  # 输出: 0

1.5 None 值

None 表示空值,等价于 Java 的 null。

python 复制代码
# None 表示空值
a = None
print(a)  # 输出: None

1.6 列表(list)

列表是 Python 中最常用的数据结构,相当于 Java 的 ArrayList。

python 复制代码
# 列表
a = [1, 2, 3]
print(a)  # 输出: [1, 2, 3]

# 列表支持混合类型
mixed_list = [1, "hello", 3.14, True]
print(mixed_list)  # 输出: [1, 'hello', 3.14, True]

# 列表常用操作
a.append(4)      # 添加元素到末尾
a.insert(0, 0)   # 在指定位置插入
a.pop()          # 删除最后一个元素
a.remove(2)      # 删除指定值的元素

二、数据结构进阶

2.1 元组(tuple)

元组是不可变的序列,一旦创建就不能修改。

python 复制代码
# 元组
t = (1, 2, 3)
print(t)  # 输出: (1, 2, 3)

# 尝试修改会报错
# t[0] = 99  # TypeError: 'tuple' object does not support item assignment

# 元组解包
a, b, c = t
print(a, b, c)  # 输出: 1 2 3

2.2 字典(dict)

字典是键值对集合,相当于 Java 的 HashMap。

python 复制代码
# 字典
d = {"name": "Alice", "age": 25}
print(d)  # 输出: {'name': 'Alice', 'age': 25}

# 添加键值对
d["email"] = "alice@example.com"

# 访问值
print(d["name"])  # 输出: Alice
print(d.get("age"))  # 输出: 25

# 删除键值对
del d["age"]

2.3 集合(set)

集合是无序不重复元素的集合,相当于 Java 的 HashSet。

python 复制代码
# 集合
s = {1, 2, 3, 3, 2}  # 自动去重
print(s)  # 输出: {1, 2, 3}

# 添加元素
s.add(4)

# 集合运算
s1 = {1, 2, 3}
s2 = {3, 4, 5}
print(s1 | s2)  # 并集: {1, 2, 3, 4, 5}
print(s1 & s2)  # 交集: {3}
print(s1 - s2)  # 差集: {1, 2}

三、控制流程

3.1 条件判断

python 复制代码
x = 10

if x > 10:
    print("大于10")
elif x == 10:
    print("等于10")
else:
    print("小于10")

3.2 循环

python 复制代码
# for 循环 - 迭代
for i in range(5):  # 0-4
    print(i)

# 遍历列表
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
    print(fruit)

# while 循环
count = 0
while count < 5:
    print(count)
    count += 1

3.3 异常处理

python 复制代码
try:
    result = 10 / 0
except ZeroDivisionError as e:
    print(f"除零错误: {e}")
except Exception as e:
    print(f"其他错误: {e}")
else:
    print("没有异常发生")
finally:
    print("无论如何都会执行")

四、函数与模块

4.1 函数定义

python 复制代码
def add(a, b=0):  # 默认参数
    """加法函数"""
    return a + b

result = add(10, 20)  # 30
result = add(10)      # 10(使用默认值)

4.2 模块导入

python 复制代码
import math
from utils import logger
from utils.logger import get_logger as gl

五、面向对象编程

5.1 类定义

python 复制代码
class Person:
    # 类属性(所有实例共享)
    species = "Homo sapiens"
    
    # 构造方法
    def __init__(self, name, age):
        self.name = name  # 实例属性
        self.age = age
    
    # 实例方法
    def greet(self):
        print(f"Hello, {self.name}")
    
    # 类方法
    @classmethod
    def get_species(cls):
        return cls.species
    
    # 静态方法
    @staticmethod
    def is_adult(age):
        return age >= 18

5.2 继承

python 复制代码
class Student(Person):
    def __init__(self, name, age, grade):
        super().__init__(name, age)  # 调用父类构造
        self.grade = grade
    
    def study(self):
        print(f"{self.name} is studying in grade {self.grade}")

5.3 多态

python 复制代码
class Dog:
    def speak(self):
        return "Woof!"

class Cat:
    def speak(self):
        return "Meow!"

def animal_sound(animal):
    print(animal.speak())

dog = Dog()
cat = Cat()
animal_sound(dog)  # Woof!
animal_sound(cat)  # Meow!

5.4 封装

python 复制代码
class BankAccount:
    def __init__(self, balance):
        self.__balance = balance  # 私有属性(约定用双下划线)
    
    def deposit(self, amount):
        if amount > 0:
            self.__balance += amount
    
    def get_balance(self):
        return self.__balance

六、Python 进阶特性

6.1 列表推导式

python 复制代码
# 生成 0-9 的平方列表
squares = [x**2 for x in range(10)]

# 带条件的列表推导
even_squares = [x**2 for x in range(10) if x % 2 == 0]

# 字典推导式
squares_dict = {x: x**2 for x in range(5)}

6.2 生成器

python 复制代码
def fibonacci(n):
    a, b = 0, 1
    for _ in range(n):
        yield a
        a, b = b, a + b

for num in fibonacci(10):
    print(num)

6.3 装饰器

python 复制代码
def logger(func):
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__}")
        result = func(*args, **kwargs)
        print(f"Done")
        return result
    return wrapper

@logger
def add(a, b):
    return a + b

6.4 上下文管理器

python 复制代码
with open("file.txt", "r") as f:
    content = f.read()
# 文件自动关闭

七、文件操作

7.1 读写文件

python 复制代码
# 写入文件
with open("output.txt", "w", encoding="utf-8") as f:
    f.write("Hello, World!")

# 读取文件
with open("output.txt", "r", encoding="utf-8") as f:
    content = f.read()
    print(content)

7.2 JSON 操作

python 复制代码
import json

# 写入 JSON
data = {"name": "Alice", "age": 25}
with open("data.json", "w", encoding="utf-8") as f:
    json.dump(data, f)

# 读取 JSON
with open("data.json", "r", encoding="utf-8") as f:
    data = json.load(f)
    print(data)

八、Python 常见"坑"与注意事项

8.1 可变默认参数陷阱

python 复制代码
# ❌ 错误示例
def add_item(item, lst=[]):
    lst.append(item)
    return lst

add_item(1)  # [1]
add_item(2)  # [1, 2] ❌ 不是预期的 [2]

# ✅ 正确示例
def add_item(item, lst=None):
    if lst is None:
        lst = []
    lst.append(item)
    return lst

8.2 浅拷贝与深拷贝

python 复制代码
import copy

# 浅拷贝
a = [1, 2, [3, 4]]
b = a.copy()
b[2][0] = 99
print(a)  # [1, 2, [99, 4]] ❌ 内部列表被修改

# 深拷贝
c = copy.deepcopy(a)
c[2][0] = 88
print(a)  # [1, 2, [99, 4]] ✅ 原列表不受影响

8.3 布尔值陷阱

python 复制代码
# ❌ 错误示例
if x = None:  # 语法错误,不能在条件中赋值(应该用 == 或 is)
    pass

# ✅ 正确示例
if x is None:  # 使用 is 判断 None(推荐)
    pass

# ✅ 也可以使用 ==
if x == None:  # 也能工作,但不推荐
    pass

注意: Python 中判断 None 推荐使用 is 而不是 ==,因为 is 比较的是对象身份,而 == 比较的是值。

8.4 字符串不可变

python 复制代码
s = "hello"
# s[0] = 'H'  # ❌ TypeError: 'str' object does not support item assignment
s = s.upper()  # ✅ 返回新字符串

九、Python 实用技巧(自动化测试必备)

9.1 f-string 格式化字符串(Python 3.6+)

f-string 是最推荐的字符串格式化方式,简洁高效。

python 复制代码
name = "Alice"
age = 25

# 基本用法
print(f"姓名: {name}, 年龄: {age}")  # 输出: 姓名: Alice, 年龄: 25

# 表达式计算
print(f"明年年龄: {age + 1}")  # 输出: 明年年龄: 26

# 调用方法
print(f"姓名大写: {name.upper()}")  # 输出: 姓名大写: ALICE

# 字典访问
data = {"status": 200, "message": "OK"}
print(f"状态码: {data['status']}, 消息: {data['message']}")

# 格式化数字
pi = 3.1415926
print(f"π 保留两位小数: {pi:.2f}")  # 输出: π 保留两位小数: 3.14

9.2 类型注解(Type Hints)

类型注解帮助 IDE 提供更好的代码提示,提高代码可读性。

python 复制代码
from typing import List, Dict, Optional, Union

# 基本类型注解
def greet(name: str) -> str:
    return f"Hello, {name}"

# 列表类型
def process_items(items: List[str]) -> int:
    return len(items)

# 字典类型
def get_user_info(user_id: int) -> Dict[str, str]:
    return {"id": str(user_id), "name": "Alice"}

# 可选类型(可能为 None)
def find_user(user_id: int) -> Optional[str]:
    if user_id == 1:
        return "Alice"
    return None

# 联合类型
def parse_value(value: Union[str, int]) -> str:
    return str(value)

9.3 pathlib 模块(现代文件操作)

pathlib 是 Python 3.4+ 引入的面向对象路径操作库,比 os.path 更优雅。

python 复制代码
from pathlib import Path

# 创建路径对象
project_root = Path(__file__).parent.parent
config_file = project_root / "config" / "config.yaml"

# 检查文件是否存在
if config_file.exists():
    print(f"配置文件存在: {config_file}")

# 读取文件内容
content = config_file.read_text(encoding="utf-8")

# 写入文件内容
output_file = project_root / "output" / "result.txt"
output_file.parent.mkdir(parents=True, exist_ok=True)  # 创建目录
output_file.write_text("Hello, World!", encoding="utf-8")

# 遍历目录
log_dir = project_root / "logs"
for log_file in log_dir.glob("*.log"):
    print(f"日志文件: {log_file.name}")

9.4 *args 和 **kwargs

用于接收可变数量的参数,在装饰器和通用函数中非常有用。

python 复制代码
# *args 接收任意数量的位置参数
def sum_all(*args):
    return sum(args)

print(sum_all(1, 2, 3))  # 输出: 6
print(sum_all(1, 2, 3, 4, 5))  # 输出: 15

# **kwargs 接收任意数量的关键字参数
def print_config(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_config(host="localhost", port=8080, debug=True)
# 输出:
# host: localhost
# port: 8080
# debug: True

# 组合使用
def flexible_function(required, *args, **kwargs):
    print(f"必需参数: {required}")
    print(f"位置参数: {args}")
    print(f"关键字参数: {kwargs}")

flexible_function("req", 1, 2, name="Alice", age=25)

十、Python 与 Java 的核心差异

10.1 类型系统

特性 Python Java
类型检查 动态类型 静态类型
变量声明 a = 1 int a = 1;
类型转换 自动 需要显式转换
泛型 无需泛型 必须使用泛型

10.2 语法差异

特性 Python Java
代码块 缩进 花括号 {}
分号 不需要 必须
注释 # 单行,''' ''' 多行 // 单行,/* */ 多行
字符串 单引号/双引号均可 只能双引号
布尔值 True/False(首字母大写) true/false(小写)
空值 None null

10.3 内存管理

特性 Python Java
垃圾回收 引用计数 + 自动回收 JVM 垃圾回收器
内存泄漏 循环引用可能导致 较少见

十一、Python 生态与工具

11.1 包管理

bash 复制代码
# 安装包
pip install requests

# 卸载包
pip uninstall requests

# 查看已安装包
pip list

# 导出依赖
pip freeze > requirements.txt

# 安装依赖
pip install -r requirements.txt

11.2 虚拟环境

bash 复制代码
# 创建虚拟环境
python -m venv venv

# 激活虚拟环境(Windows)
venv\Scripts\activate

# 激活虚拟环境(Linux/Mac)
source venv/bin/activate

# 退出虚拟环境
deactivate

十二、自动化测试专项

12.1 pytest 测试框架详解

12.1.1 pytest 简介

pytest 是 Python 中最流行的测试框架,相比 Java 的 JUnit 更简洁、更强大。

核心特点:

  • 简单易用,学习曲线平缓
  • 自动发现测试文件和测试用例
  • 支持参数化测试
  • 强大的 fixture 机制(替代 JUnit 的 setUp/tearDown)
  • 丰富的插件生态(测试报告、覆盖率等)

安装:

bash 复制代码
pip install pytest pytest-html
12.1.2 测试用例编写

基本规则

  • 测试文件以 test_ 开头或 _test.py 结尾
  • 测试类以 Test 开头(首字母大写)
  • 测试方法以 test_ 开头
  • 使用 assert 进行断言

示例:简单测试用例

python 复制代码
# test_example.py
def test_addition():
    """测试加法运算"""
    assert 1 + 2 == 3

def test_string_equal():
    """测试字符串相等"""
    assert "hello" == "hello"

class TestMath:
    """数学运算测试类"""
    
    def test_multiply(self):
        """测试乘法"""
        assert 2 * 3 == 6
    
    def test_divide(self):
        """测试除法"""
        assert 10 / 2 == 5
12.1.3 pytest Fixture(夹具)

Fixture 是 pytest 中最强大的功能之一,用于管理测试依赖和共享资源。

基本用法

python 复制代码
import pytest

# 定义 fixture
@pytest.fixture
def setup_data():
    """准备测试数据"""
    print("\nSetup: 准备数据")
    data = {"name": "test", "value": 100}
    
    yield data  # 提供测试数据给测试用例
    
    print("\nTeardown: 清理数据")  # 测试完成后执行

# 使用 fixture
def test_use_fixture(setup_data):
    assert setup_data["name"] == "test"
    assert setup_data["value"] == 100

Fixture 作用域

作用域 说明 生命周期
function 默认,每个测试函数 每个测试函数执行一次
class 每个测试类 每个测试类执行一次
module 每个模块 每个模块执行一次
session 整个测试会话 整个测试会话执行一次
python 复制代码
@pytest.fixture(scope="session")
def session_fixture():
    """整个测试会话只执行一次"""
    print("Session setup")
    yield
    print("Session teardown")

conftest.py 文件

conftest.py 是 pytest 的特殊配置文件,用于存放共享的 fixture。pytest 会自动发现并加载它。

python 复制代码
# tests/conftest.py
import pytest
import yaml
import os

@pytest.fixture(scope="session")
def config():
    """读取配置文件"""
    config_path = os.path.join(os.path.dirname(__file__), "..", "config", "config.yaml")
    with open(config_path, "r", encoding="utf-8") as f:
        return yaml.safe_load(f)

@pytest.fixture(scope="function")
def logger():
    """获取日志记录器"""
    from utils.logger import get_logger
    return get_logger("test")
12.1.4 参数化测试

使用 @pytest.mark.parametrize 实现参数化测试,减少重复代码。

基本参数化

python 复制代码
import pytest

@pytest.mark.parametrize("a, b, expected", [
    (1, 2, 3),      # 用例1:正常加法
    (0, 0, 0),      # 用例2:边界情况
    (-1, 1, 0),     # 用例3:负数相加
    (1.5, 2.5, 4.0), # 用例4:小数相加
])
def test_add_parametric(a, b, expected):
    """参数化测试加法运算"""
    assert a + b == expected

带 ID 的参数化

python 复制代码
@pytest.mark.parametrize(
    "a, b, expected",
    [
        (10, 20, 30),
        (0, 0, 0),
        (-5, -10, -15),
    ],
    ids=["正常加法", "零操作数", "负数相加"]  # 自定义用例名称
)
def test_add_with_ids(a, b, expected):
    assert a + b == expected

从 JSON 文件读取参数化数据

python 复制代码
import pytest
import json

# 从 JSON 文件加载测试数据
with open("test_data/parametric_test_data.json", "r", encoding="utf-8") as f:
    test_data = json.load(f)["parametric_test"]["test_cases"]

@pytest.mark.parametrize(
    "case_data",
    test_data,
    ids=[case["case_id"] for case in test_data]
)
def test_from_json(case_data):
    """从 JSON 文件读取测试数据"""
    result = case_data["a"] + case_data["b"]
    assert result == case_data["expected_result"]
12.1.5 断言

pytest 支持 Python 原生 assert,并能自动生成详细的错误信息。

常用断言方式

python 复制代码
def test_assertions():
    # 基本断言
    assert 1 + 1 == 2
    
    # 断言包含
    assert "hello" in "hello world"
    
    # 断言不相等
    assert 1 != 2
    
    # 断言为真/假
    assert True
    assert not False
    
    # 断言异常
    with pytest.raises(ZeroDivisionError):
        1 / 0
    
    # 断言异常并检查消息
    with pytest.raises(ValueError, match="invalid literal"):
        int("abc")
12.1.6 测试标记

使用标记对测试用例进行分类,支持分场景执行。

定义标记

pytest.inipyproject.toml 中配置:

ini 复制代码
[pytest]
markers =
    smoke: 冒烟测试用例
    regression: 回归测试用例
    api: 接口测试用例
    ui: UI测试用例

使用标记

python 复制代码
import pytest

@pytest.mark.smoke
def test_critical_function():
    """冒烟测试:关键功能"""
    pass

@pytest.mark.api
@pytest.mark.regression
def test_api_function():
    """接口回归测试"""
    pass

按标记运行测试

bash 复制代码
# 运行冒烟测试
python -m pytest -m smoke

# 运行接口测试
python -m pytest -m api

# 排除某个标记
python -m pytest -m "not ui"

# 组合标记
python -m pytest -m "api and regression"
12.1.7 测试报告

生成 HTML 报告

bash 复制代码
# 生成 HTML 报告
python -m pytest --html=reports/report.html

# 生成详细报告(包含失败详情)
python -m pytest --html=reports/report.html --self-contained-html

常用命令行参数

bash 复制代码
# 显示详细输出
python -m pytest -v

# 只运行失败的测试
python -m pytest --lf

# 显示测试耗时
python -m pytest --durations=10

# 运行指定文件
python -m pytest tests/test_example.py

# 运行指定测试类
python -m pytest tests/test_example.py::TestMath

# 运行指定测试方法
python -m pytest tests/test_example.py::TestMath::test_multiply

# 停止于第一个失败
python -m pytest -x

# 显示打印输出
python -m pytest -s
12.1.8 与 Java JUnit 的对比
特性 pytest JUnit
测试发现 自动发现 test_ 开头 需要注解 @Test
前置/后置 fixture @Before/@After
参数化 @pytest.mark.parametrize @ParameterizedTest
断言 原生 assert assertEquals()
测试报告 插件 pytest-html 插件 surefire-report
标记 @pytest.mark @Tag

12.2 requests 库(接口测试)

requests 是 Python 最流行的 HTTP 库,用于接口测试。

12.2.1 基本用法
python 复制代码
import requests

# GET 请求
response = requests.get("https://api.example.com/users", timeout=10)
print(response.status_code)  # 状态码
print(response.json())       # JSON 响应
print(response.text)         # 文本响应

# POST 请求(JSON)
data = {"name": "Alice", "age": 25}
response = requests.post(
    "https://api.example.com/users",
    json=data,  # 自动序列化为 JSON
    timeout=10
)

# POST 请求(表单)
form_data = {"username": "admin", "password": "123456"}
response = requests.post(
    "https://api.example.com/login",
    data=form_data,  # 表单数据
    timeout=10
)

# 带请求头
headers = {
    "Authorization": "Bearer token123",
    "Content-Type": "application/json"
}
response = requests.get(
    "https://api.example.com/protected",
    headers=headers,
    timeout=10
)

# 带查询参数
params = {"page": 1, "limit": 10}
response = requests.get(
    "https://api.example.com/users",
    params=params,  # 自动拼接到 URL
    timeout=10
)
12.2.2 异常处理
python 复制代码
import requests
from requests.exceptions import RequestException, Timeout, ConnectionError

try:
    response = requests.get("https://api.example.com/users", timeout=10)
    response.raise_for_status()  # 如果状态码不是 2xx,抛出异常
    data = response.json()
    print(data)
except Timeout:
    print("请求超时")
except ConnectionError:
    print("连接失败")
except RequestException as e:
    print(f"请求异常: {e}")
12.2.3 Session 对象

Session 可以保持会话状态(如 Cookie),适合需要登录的场景。

python 复制代码
import requests

# 创建会话
session = requests.Session()

# 登录
login_data = {"username": "admin", "password": "123456"}
session.post("https://api.example.com/login", json=login_data)

# 后续请求会自动携带 Cookie
response = session.get("https://api.example.com/profile")
print(response.json())

# 设置通用请求头
session.headers.update({"Authorization": "Bearer token123"})

# 关闭会话
session.close()
12.2.4 实战示例
python 复制代码
import pytest
import requests

@pytest.fixture(scope="module")
def api_client():
    """API 测试客户端"""
    session = requests.Session()
    session.headers.update({"Content-Type": "application/json"})
    yield session
    session.close()

class TestUserAPI:
    """用户接口测试类"""
    
    @pytest.mark.api
    def test_get_user(self, api_client):
        """测试获取用户信息"""
        response = api_client.get("https://api.example.com/users/1", timeout=10)
        assert response.status_code == 200
        data = response.json()
        assert "id" in data
        assert "name" in data
    
    @pytest.mark.api
    @pytest.mark.parametrize("user_id", [1, 2, 3])
    def test_get_user_parametric(self, api_client, user_id):
        """参数化测试获取不同用户"""
        response = api_client.get(f"https://api.example.com/users/{user_id}", timeout=10)
        assert response.status_code == 200

12.3 Selenium(UI 自动化测试)

Selenium 是 Web UI 自动化测试的标准工具。

12.3.1 基本用法
python 复制代码
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.service import Service

# 创建浏览器驱动
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)

# 打开网页
driver.get("https://www.baidu.com")

# 元素定位
search_box = driver.find_element(By.ID, "kw")
search_button = driver.find_element(By.ID, "su")

# 输入文本
search_box.send_keys("自动化测试")

# 点击按钮
search_button.click()

# 显式等待(推荐)
wait = WebDriverWait(driver, 10)
result = wait.until(
    EC.presence_of_element_located((By.CSS_SELECTOR, ".result"))
)

# 获取文本
print(result.text)

# 关闭浏览器
driver.quit()
12.3.2 元素定位方式
python 复制代码
# ID 定位
element = driver.find_element(By.ID, "element_id")

# CSS Selector 定位(推荐)
element = driver.find_element(By.CSS_SELECTOR, ".class_name")
element = driver.find_element(By.CSS_SELECTOR, "#id_name")
element = driver.find_element(By.CSS_SELECTOR, "div > p")

# XPath 定位
element = driver.find_element(By.XPATH, "//div[@class='test']")

# 名称定位
element = driver.find_element(By.NAME, "username")

# 标签名定位
elements = driver.find_elements(By.TAG_NAME, "input")

# 链接文本定位
element = driver.find_element(By.LINK_TEXT, "点击这里")
12.3.3 Page Object 模式

Page Object 是 UI 自动化的最佳实践,将页面元素和操作封装成类。

python 复制代码
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

class BaiduHomePage:
    """百度首页页面对象"""
    
    def __init__(self, driver):
        self.driver = driver
        self.search_box = (By.ID, "kw")
        self.search_button = (By.ID, "su")
    
    def open(self):
        """打开百度首页"""
        self.driver.get("https://www.baidu.com")
        return self
    
    def search(self, keyword):
        """搜索关键词"""
        search_input = WebDriverWait(self.driver, 10).until(
            EC.visibility_of_element_located(self.search_box)
        )
        search_input.clear()
        search_input.send_keys(keyword)
        
        search_btn = self.driver.find_element(*self.search_button)
        search_btn.click()
        
        return BaiduSearchResultPage(self.driver)

class BaiduSearchResultPage:
    """百度搜索结果页面对象"""
    
    def __init__(self, driver):
        self.driver = driver
        self.result_container = (By.CSS_SELECTOR, ".result")
    
    def get_result_count(self):
        """获取结果数量"""
        results = self.driver.find_elements(*self.result_container)
        return len(results)
    
    def is_keyword_in_results(self, keyword):
        """检查关键词是否在结果中"""
        page_source = self.driver.page_source
        return keyword in page_source

# 使用示例
def test_baidu_search(driver):
    home_page = BaiduHomePage(driver)
    result_page = home_page.open().search("自动化测试")
    
    assert result_page.get_result_count() > 0
    assert result_page.is_keyword_in_results("自动化测试")
12.3.4 pytest + Selenium 集成
python 复制代码
import pytest
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager

@pytest.fixture(scope="function")
def driver():
    """浏览器驱动 fixture"""
    service = Service(ChromeDriverManager().install())
    options = webdriver.ChromeOptions()
    # options.add_argument('--headless')  # 无头模式
    driver = webdriver.Chrome(service=service, options=options)
    driver.implicitly_wait(10)  # 隐式等待
    yield driver
    driver.quit()  # 测试结束后关闭浏览器

def test_baidu_homepage(driver):
    """测试百度首页"""
    driver.get("https://www.baidu.com")
    assert "百度" in driver.title

12.4 YAML 配置文件读取

YAML 是常用的配置文件格式,比 JSON 更易读。

python 复制代码
import yaml

# 读取 YAML 文件
with open("config/config.yaml", "r", encoding="utf-8") as f:
    config = yaml.safe_load(f)

# 访问配置项
base_url = config["base_url"]
timeout = config["timeout"]
browser_type = config["browser"]["type"]

print(f"基础URL: {base_url}")
print(f"超时时间: {timeout}")
print(f"浏览器: {browser_type}")

config.yaml 示例:

yaml 复制代码
environment: development
base_url: http://localhost:8080
timeout: 30

browser:
  type: chrome
  headless: true
  implicit_wait: 10

api:
  username: test_user
  password: test_password

十三、项目实战指南

13.1 项目结构

复制代码
auto-test-framework/
├── config/              # 配置文件
│   └── config.yaml      # 主配置文件
├── test_data/           # 测试数据
│   ├── api/             # 接口测试数据
│   └── ui/              # UI测试数据
├── tests/               # 测试用例
│   ├── api/             # 接口测试
│   ├── ui/              # UI测试
│   ├── conftest.py      # 共享fixture
│   └── demo/            # 示例测试
├── utils/               # 工具函数
│   ├── logger.py        # 日志工具
│   └── helpers.py       # 辅助函数
├── pages/               # 页面对象(UI测试)
├── reports/             # 测试报告
├── logs/                # 日志文件
├── pytest.ini           # pytest配置
├── pyproject.toml       # 项目配置
└── requirements.txt     # 依赖清单

13.2 开发流程

  1. 编写测试数据 :在 test_data/ 目录下创建 JSON/YAML 文件
  2. 编写测试用例 :在 tests/ 目录下创建测试文件
  3. 运行测试python -m pytest -v
  4. 查看报告 :打开 reports/report.html
  5. 调试优化:根据测试结果修复问题

13.3 最佳实践

  1. 测试数据分离:不要在代码中硬编码测试数据
  2. 使用 fixture:复用初始化代码
  3. 参数化测试:一套逻辑覆盖多种场景
  4. 异常处理:精准捕获预期异常
  5. 日志记录:关键步骤记录日志
  6. 断言明确:添加清晰的错误消息
  7. 代码复用:提取公共方法到 utils

13.4 常见问题排查

问题1:测试用例未被发现

  • 检查文件名是否以 test_ 开头
  • 检查类名是否以 Test 开头
  • 检查方法名是否以 test_ 开头

问题2:fixture 未生效

  • 检查 conftest.py 是否在正确的目录
  • 检查 fixture 名称是否与参数名一致
  • 检查 scope 是否合适

问题3:导入错误

  • 检查项目根目录是否有 __init__.py
  • 检查 PYTHONPATH 是否包含项目根目录
  • 使用绝对导入而非相对导入

问题4:中文乱码

  • 文件读写时指定 encoding="utf-8"
  • JSON 文件保存时使用 ensure_ascii=False

十四、Python 知识体系总结

14.1 Python 知识点概览

Python 的知识体系其实非常庞大,远不止文档中这些内容。以下是完整的 Python 知识体系:

基础语法
  • 变量与数据类型
  • 运算符与表达式
  • 控制流程(if/for/while)
  • 函数定义与调用
  • 异常处理
数据结构
  • 列表(list)
  • 元组(tuple)
  • 字典(dict)
  • 集合(set)
  • 字符串(str)
  • 字节(bytes)
面向对象
  • 类与对象
  • 继承与多态
  • 封装
  • 魔术方法
  • 元类(metaclass)
进阶特性
  • 装饰器
  • 生成器
  • 迭代器
  • 上下文管理器
  • 列表推导式
  • Lambda 表达式
  • 类型注解(typing)
并发编程
  • 多线程(threading)
  • 多进程(multiprocessing)
  • 协程(asyncio)
  • 并发安全(锁、信号量)
网络编程
  • Socket 编程
  • HTTP 请求(requests)
  • Web 框架(Flask/Django)
  • WebSocket
数据处理
  • 文件操作(os/pathlib)
  • JSON/YAML 处理
  • CSV/Excel 处理
  • 数据库操作(SQLAlchemy)
测试框架
  • pytest
  • unittest
  • mock
  • coverage
工具与生态
  • 包管理(pip)
  • 虚拟环境(venv)
  • 代码格式化(black)
  • 类型注解(typing)
专项领域
  • 数据科学(NumPy/Pandas)
  • 机器学习(scikit-learn)
  • Web 开发(Django/Flask)
  • 自动化测试(Selenium/requests)
  • 数据可视化(Matplotlib)

14.2 学习建议

  1. 循序渐进:从基础语法开始,逐步深入
  2. 实践为主:多写代码,多做项目
  3. 查阅文档:遇到问题查阅官方文档
  4. 参与社区:加入 Python 社区,交流学习
  5. 阅读源码:学习优秀开源项目的代码风格

最后更新: 2026-05-25