修复Flask-WTF自定义验证器的pytest测试AttributeError问题
Flask-WTF自定义密码验证器错误修复
问题分析
make_password_contain_capital的参数定义是正确的——Flask-WTF自定义验证器的标准签名就是(form, field),其中field是WTForms的字段实例,自带data属性。报错的直接原因是测试代码中传入了字符串作为field参数,而字符串没有data属性,触发AttributeError。
同时代码还存在两个额外问题:
raise ValidationError语句的括号未闭合,存在语法错误- 在验证器中调用
flash不符合职责划分,验证器仅需完成校验并抛出错误,提示逻辑应放在表单处理流程中
修复步骤
1. 修复自定义验证器代码(auth/functions.py)
from wtforms import ValidationError def make_password_contain_capital(form, field): ''' 验证密码是否包含大写字母,不包含则抛出ValidationError 用于RegistrationForm的password和confirm_password字段 ''' password = field.data # 检查是否存在大写字母 has_capital = any(char.isupper() for char in password) if not has_capital: raise ValidationError("密码必须包含至少一个大写字母") # 验证通过无需额外操作,Flask-WTF会自动处理后续流程
2. 修复测试代码(tests/non_db_functions/login_routes.py)
测试时需要传入符合要求的field对象(带有data属性),可以用unittest.mock模拟字段,或直接使用表单的实际字段:
from app.auth.functions import make_password_contain_capital from wsgi import app from app.auth.forms import LoginForm from wtforms.validators import ValidationError import pytest from unittest.mock import Mock # 测试用例1:密码包含大写字母,验证通过不报错 def test_password_with_capital(): with app.test_request_context(): form = LoginForm() # 模拟WTForms字段对象 mock_field = Mock() mock_field.data = 'Aejfpwo;fkjeo;' # 验证通过,不应抛出异常 make_password_contain_capital(form, mock_field) # 测试用例2:密码无大写字母,验证失败抛出异常 def test_password_without_capital(): with app.test_request_context(): form = LoginForm() mock_field = Mock() mock_field.data = 'aejfpwo;fkjeo;' with pytest.raises(ValidationError): make_password_contain_capital(form, mock_field)
如果不想用Mock,也可以直接操作表单的实际字段:
def test_password_without_capital(): with app.test_request_context(): form = LoginForm(password='aejfpwo;fkjeo;') # 假设LoginForm中定义了password字段 make_password_contain_capital(form, form.password)
3. 修正测试逻辑
原测试代码逻辑矛盾:传入包含大写的密码,却期望抛出ValidationError,与验证器逻辑相悖。修正后拆分两个测试用例,分别覆盖“验证通过”和“验证失败”场景。
运行测试
保持原命令执行即可:
$env:FLASK_ENV="pytest" pytest -q --capture=no
内容的提问来源于stack exchange,提问作者jrgop
相关产品推荐
相关产品推荐

