我最近看了一下假设,并像这样使用它:
import hypothesis.strategies as s
from hypothesis import given
@given(s.integers(min_value=-(10 ** 6), max_value=10 ** 6))
def test_factorize(an_integer):
if an_integer == 0:
# This is tested in `test_factorize_zero` and should throw an exception
return
factors = mpu.math.factorize(an_integer)
product = 1
for factor in factors:
product *= factor
assert product == an_integer
这很酷。我看到的主要限制是策略(例如s.integers
(,尽管有很多策略,但我仍在学习哪些策略/如何正确使用它们。
是否有一种策略来生成对象,给定一个使用 pydantic 的类型注释类?
我的尝试
from typing import Optional
from hypothesis import given
from hypothesis.strategies import from_type
from pydantic import BaseModel
class Adress(BaseModel):
city: str
street: str
house_number: int
postal_code: int
class Person(BaseModel):
prename: str
middlename: Optional[str]
lastname: str
address: Adress
@given(from_type(Person))
def test_me(person: Person):
assert isinstance(person, Person)
当我将其保存为test_foo.py
并执行pytest
时,我得到:
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― test_me ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
@given(from_type(Person))
> def test_me(person: Person):
test_foo.py:20:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E pydantic.error_wrappers.ValidationError: 3 validation errors for Person
E prename
E field required (type=value_error.missing)
E lastname
E field required (type=value_error.missing)
E address
E field required (type=value_error.missing)
pydantic/main.py:283: ValidationError
---------------------------------------------------------------- Hypothesis ----------------------------------------------------------------
You can add @seed(42732672939050403878146949573829059697) to this test or run pytest with --hypothesis-seed=42732672939050403878146949573829059697 to reproduce this failure.
如果假设产生了一个没有中间名的人和一个有中间名的人,我会特别喜欢。
这不会开箱即用,因为 Hypothesis 需要知道使用什么类型来构建 pydantic 模型,而且我们没有特别支持 pydantic(我实际上只是从这篇文章中听说过它(。
为了支持它,可以做两件事:
- pydantic 可以生成正确类型的
__init__
方法。一个 pydantic__init__
方法的签名是__pydantic_self__, **data:Any
的,所以我们没有办法知道它期望什么参数。相反,如果类型签名与字段参数的类型签名匹配,则假设将开箱即用。 - 有人可以编写一个 PR 来为假设的
from_type
实现添加 pydantic 支持,以便它知道如何构建 pydantic 模型。我们已经有了对 attrs 和数据类的自定义支持,这大多看起来像这样。
如果 pydantic 开发人员对它持开放态度,我的首选解决方案将是第一个。
同时,您可以使用builds
函数为模型定义自定义策略。然后,您可以将其注册为该类型的策略,也可以直接使用它。