Pytest断言函数类外调用问题及reconciler.py中getLogger调用验证失败求助
一、先解决你的Logger测试失败问题
你的测试用例有两个关键问题,导致断言logger.called返回False:
1. 模块初始化时机与Patch顺序错误
在reconciler.py中,logger = getLogger()是模块级别的代码,会在模块第一次被导入时执行。如果你的测试用例在patch之前就已经导入了reconciler,那么getLogger()在Patch生效前就已经被调用了,后续的Patch根本无法拦截这个调用。
2. 测试用例未触发模块加载
你的测试代码里没有导入reconciler模块,所以模块级别的getLogger()根本没有被执行的机会,自然不会触发调用。
修正后的测试用例
你需要确保在patch生效后再导入(或重新加载)reconciler模块,这样才能让getLogger()调用被Mock捕获:
from unittest.mock import patch import importlib import reconciler # 如果之前已经导入过,需要重新加载 class TestLogger(MyTestCase): def test_logger(self): with patch("service.type.logger.getLogger") as mock_get_logger: # 重新加载模块,确保模块初始化代码在Patch后执行 importlib.reload(reconciler) # 验证Mock被调用 assert mock_get_logger.called
或者,更稳妥的方式是在Patch上下文内首次导入模块:
from unittest.mock import patch class TestLogger(MyTestCase): def test_logger(self): with patch("service.type.logger.getLogger") as mock_get_logger: # 在这里导入,确保模块加载时使用Mock的getLogger import reconciler assert mock_get_logger.called
另外,注意你的reconciler.py里有个语法错误:get_or_create_obj应该是函数(用def定义),而不是类(class),否则代码运行会报错,修正后如下:
from service.type.logger import getLogger logger = getLogger() # 修正为def定义函数 def get_or_create_obj(model_class, is_new_asset, **kwargs): if is_new_asset: return model_class.objects.create(**kwargs) else: obj, created = model_class.objects.get_or_create(**kwargs) return obj
二、关于Pytest断言函数在类外调用的疑问
Pytest的assert断言语句完全可以在类外部使用,没有限制,只要是在Pytest运行的代码路径中,断言失败都会被捕获并标记为测试失败。常见的使用场景包括:
模块级代码:直接在脚本顶部写断言(不过一般不推荐,除非是初始化校验)
# 模块级别断言 CONFIG = load_config() assert CONFIG.get("db_url"), "数据库URL未配置"普通函数:在业务函数中加入断言做参数或结果校验
def calculate_discount(price, rate): assert 0 < rate <= 1, "折扣率必须在(0,1]范围内" return price * rate类外的测试函数:Pytest支持直接定义类外的测试函数,不需要包裹在测试类中
# 类外的测试用例 def test_calculate_discount(): assert calculate_discount(100, 0.8) == 80 with pytest.raises(AssertionError): calculate_discount(100, 1.5)
需要注意的是:如果断言写在测试类的方法外部(比如类的顶层),这部分代码会在测试类加载时执行,而不是作为测试用例的一部分,所以即使断言失败,Pytest也不会将其标记为测试失败,而是直接报错终止测试运行。
内容的提问来源于stack exchange,提问作者user4981459

