Pytest与Google App Engine Testbed:预期验证错误却致测试失败?
解决pytest测试GAE ndb模型验证异常时的测试失败问题
问题分析
你的测试代码中,虽然预期m.put()会抛出验证异常,但实际异常是在创建MyModel实例并赋值value属性时就触发了(ndb的属性验证默认在赋值阶段执行),而你的pytest.raises(Exception)仅包裹了m.put()调用,导致这个提前抛出的异常没有被捕获,直接造成测试失败。
另外,即使你使用put_async()不调用get_result(),异常依然会在实例创建/属性赋值阶段抛出,所以结果一致。
解决方案
1. 调整pytest.raises的包裹范围
如果验证逻辑确实在属性赋值时触发,把pytest.raises包裹在实例创建代码外:
class TestMyModel: @pytest.mark.parametrize("value", [-7, -1, 0]) def test_non_positive_value_validation_error(self, value): from models.datastore import MyModel from google.appengine.ext import ndb # 捕获属性赋值时抛出的异常 with pytest.raises(ValueError, match="must be a positive integer!"): m = MyModel( _just_created=True, value=value )
2. 若验证逻辑在put时触发(自定义验证场景)
如果你的模型是在put()方法中自定义了验证逻辑,那么需要:
- 使用具体的异常类型(如
ValueError)替代泛用的Exception,避免捕获无关异常 - 可以添加
match参数精准匹配异常信息,确保测试准确性:
class TestMyModel: @pytest.mark.parametrize("value", [-7, -1, 0]) def test_non_positive_value_validation_error(self, value): from models.datastore import MyModel from google.appengine.ext import ndb m = MyModel( _just_created=True, value=value ) # 捕获put时抛出的指定异常 with pytest.raises(ValueError, match="must be a positive integer!"): m.put()
3. 优化GAE Testbed初始化
避免使用init_all_stubs()初始化所有不必要的stub,可能会干扰测试行为,只初始化需要的stub即可:
@pytest.fixture(scope='function', autouse=True) def gae_testbed(request): from google.appengine.ext import testbed tb = testbed.Testbed() tb.activate() # 仅初始化datastore和memcache stub(根据你的测试需求调整) tb.init_datastore_v3_stub() tb.init_memcache_stub() def teardown(): tb.deactivate() request.addfinalizer(teardown) return tb
验证步骤
- 在测试代码中添加断点或print语句,确认异常抛出的具体代码行
- 对应调整
pytest.raises的包裹范围或异常类型 - 运行测试,确认异常被正确捕获,测试通过
内容的提问来源于stack exchange,提问作者Ryan Pierce Williams
相关产品推荐
相关产品推荐

