绘制具有唯一性和完整性要求的复合值列表的更简单方法?



给定一个我试图构造的对象:

from dataclasses import dataclass    
@dataclass
class Thing:
thing_id: str
a: int
b: float
# other attributes

对于基于属性的测试,我需要生成Thing列表,以便

  • item_id在列表中是唯一的
  • ab是列表[(a0, b0), (a1, b1), ...]中的配对值
  • 从该(a, b)列表中,每个值至少绘制一次

这就是我想出的:

from hypothesis import strategies as st
def thing_lists(ab):
# ab = [(a0, b0), (a1, b1), ...]
vals = (
# list that has at least all values from ab
st.lists(st.sampled_from(ab))
.flatmap(lambda sample: st.permutations(sample + ab))
# add ids
.flatmap(
# get unique ids
lambda abs: st.lists(
st.text(), min_size=len(abs), max_size=len(abs), unique=True
# zip with abs
).map(lambda ids: [(id, *ab) for id, ab in zip(ids, abs)])
)
)
return vals.flatmap(
lambda idabs: st.tuples(
*[
st.builds(
Thing,
st.just(id), 
st.just(a), 
st.just(b),
# other attributes by free choice of hypothesis
)
for (id, a, b) in idabs
]
).map(list)
)

这有效,但绘制一个元组然后将其映射到列表有点复杂;我是否错过了一种更清楚地了解正在发生的事情的不同技术?

这对我来说基本上是合理的 - 它很邋遢,但主要是因为你的要求。 我也会尝试

vals = st.lists(
st.tuples(st.text(), st.sampled_from(ab)),
min_size=len(ab),
unique_by=lambda x: x[0],
).filter(lambda ls: {x for _, x in ls}.issuperset(ab))

但显然,如果ab很长,该过滤器将是一个严格的约束,所以我只期望如果它很短(但要衡量!

如果这确实有效,你会得到比上面更快,有时更好的收缩;内联builds()部分以使每个列表元素的生成完全本地将进一步改善这一点,但可能需要一个新的构造函数。 不过,这些都不值得牺牲可读性!

最新更新