0
点赞
收藏
分享

微信扫一扫

java程序员怎么从Python小白变成Python大拿?(五)

文章5:Python中的异常处理和测试

目标

掌握Python的异常处理机制,学会编写健壮的错误处理代码,并使用单元测试和Mock技术确保代码质量。

一、异常处理基础

1. try-except-finally 结构

Python通过try-except结构捕获和处理异常,确保程序在错误发生时不会崩溃,并提供清理操作。

示例:除法运算与文件读取

try:
    # 可能引发异常的代码
    result = 10 / 0
    with open("nonexistent.txt", "r") as f:
        content = f.read()
except ZeroDivisionError as e:
    print(f"除以零错误: {e}")  # 处理除零错误
except FileNotFoundError as e:
    print(f"文件未找到: {e}")  # 处理文件不存在错误
except Exception as e:
    print(f"未知错误: {e}")    # 捕获其他所有异常
else:
    print("操作成功,无异常发生")  # 仅在无异常时执行
finally:
    print("清理资源(如关闭文件或释放资源)")  # 总是执行

2. 自定义异常类

通过继承Exception或其子类,可以创建自定义异常,提高错误信息的可读性。

示例:自定义验证异常

class InvalidAgeError(Exception):
    """当年龄无效时抛出的异常"""
    def __init__(self, age):
        self.age = age
        self.message = f"年龄 {age} 不合法(必须为1-120之间的整数)"
        super().__init__(self.message)

def validate_age(age):
    if not 1 <= age <= 120:
        raise InvalidAgeError(age)
    return True

try:
    validate_age(150)  # 触发异常
except InvalidAgeError as e:
    print(e)  # 输出:"年龄 150 不合法(必须为1-120之间的整数)"

二、单元测试框架

1. unittest 框架

Python内置的单元测试框架,通过继承TestCase类定义测试用例。

示例:计算器测试

import unittest

class Calculator:
    def add(self, a, b):
        return a + b

class TestCalculator(unittest.TestCase):
    def setUp(self):
        self.calc = Calculator()  # 每个测试用例前初始化对象

    def test_add_positive(self):
        self.assertEqual(self.calc.add(2, 3), 5)

    def test_add_negative(self):
        self.assertEqual(self.calc.add(-1, -1), -2)

    def tearDown(self):
        del self.calc  # 每个测试用例后清理资源

if __name__ == "__main__":
    unittest.main()

2. pytest 框架

更简洁的第三方测试框架,支持参数化、fixture和更灵活的语法。

示例:参数化测试

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

def test_add():
    assert add(2, 3) == 5

def test_add_negative():
    assert add(-1, -1) == -2

# 参数化测试:测试多个输入组合
import pytest

@pytest.mark.parametrize("a, b, expected", [
    (1, 2, 3),
    (0, 0, 0),
    (-5, 3, -2)
])
def test_add_param(a, b, expected):
    assert add(a, b) == expected

运行命令:

pytest test_file.py

三、Mock对象与隔离测试

1. unittest.mock 模块

通过Mockpatch模拟外部依赖,确保测试独立性。

示例:模拟API调用

from unittest.mock import patch

def fetch_data_from_api():
    # 假设这是一个外部API调用
    import requests
    return requests.get("https://api.example.com/data").json()

def get_user_data():
    response = fetch_data_from_api()
    return response.get("user", {})

# 测试时模拟API返回
class TestUserData(unittest.TestCase):
    @patch("module.requests.get")
    def test_get_user_data(self, mock_get):
        mock_response = {"user": {"id": 1, "name": "Alice"}}
        mock_get.return_value.json.return_value = mock_response
        result = get_user_data()
        self.assertEqual(result["name"], "Alice")

2. pytest-mock 插件

更简洁的Mock工具,适用于pytest。

示例:模拟文件写入

def write_to_file(content):
    with open("output.txt", "w") as f:
        f.write(content)

def test_write_to_file(mocker):
    mock_open = mocker.mock_open()
    mocker.patch("builtins.open", mock_open)
    write_to_file("Hello, Test!")
    mock_open.assert_called_once_with("output.txt", "w")
    mock_open().write.assert_called_once_with("Hello, Test!")

四、综合示例:用户注册系统

# app.py
class UserRegistrationError(Exception):
    pass

def register_user(username, email):
    if not username or not email:
        raise UserRegistrationError("用户名或邮箱不能为空")
    # 模拟数据库操作
    print(f"用户 {username} 注册成功!")

# tests/test_app.py (使用pytest)
from app import register_user
import pytest

def test_register_user_success():
    register_user("alice", "alice@example.com")  # 正常情况

def test_register_user_empty_username():
    with pytest.raises(UserRegistrationError):
        register_user("", "bob@example.com")

def test_register_user_empty_email():
    with pytest.raises(UserRegistrationError):
        register_user("bob", "")

练习题

  1. 编写一个函数,计算两个数的商,并使用try-except处理除零错误。
  2. 定义一个自定义异常InvalidURLException,并在验证URL格式时抛出。
  3. 使用unittest为一个BankAccount类编写测试,覆盖存款、取款和余额查询功能。
  4. 使用pytest-mock模拟一个依赖外部API的函数,并测试其返回值。

总结

通过掌握异常处理、单元测试和Mock技术,你可以编写更健壮、可维护的代码:

  • 异常处理:确保程序在错误时优雅地恢复或提示用户。
  • 单元测试:验证代码逻辑的正确性,减少回归风险。
  • Mock技术:隔离依赖,提高测试效率和独立性。

继续实践这些技术,你将能够构建高质量的Python应用程序!

举报

相关推荐

0 条评论