В качестве учебного проекта я перевожу некоторый код на Haskell (с которым я не знаком) на Python (который я хорошо знаю) ...
В библиотеке Haskell, которую я перевожу, есть тесты, в которых используется тестирование на основе свойств QuickCheck. Со стороны Python я использую гипотезу в качестве библиотеки тестирования на основе свойств.
В тестах Haskell используется вспомогательная функция, которая выглядит следующим образом:
mkIndent' :: String -> Int -> Gen String
mkIndent' val size = concat <$> sequence [indent, sym, trailing]
where
whitespace_char = elements " \t"
trailing = listOf whitespace_char
indent = frequency [(5, vectorOf size whitespace_char), (1, listOf whitespace_char)]
sym = return val
Мой вопрос конкретно о генераторе frequency
в этом помощнике.
http://hackage.haskell.org/package/QuickCheck-2.12.6.1/docs/Test-QuickCheck-Gen.html#v:frequency
Я понимаю, что это означает, что большую часть времени он вернет vectorOf whitespace_char
с ожидаемым size
, но 1 раз в 5 он вернет listOf whitespace_char
, который может быть любой длины, включая ноль .
В контексте библиотеки отступ, который не учитывает size
, будет моделировать неверные входные данные для тестируемой функции. Так что я вижу смысл иногда производить такой ввод.
То, что я в настоящее время не понимаю, почему соотношение 5: 1 в пользу действительных входных данных? Я ожидал, что основанная на свойствах тестовая среда будет генерировать различные допустимые и недействительные входные данные. На данный момент я предполагаю, что это что-то вроде оптимизации, так что она не тратит большую часть своего времени на создание неверных примеров?
Вторая часть моего вопроса - как перевести это в гипотезу. У гипотезы AFAICT нет эквивалента генератора frequency
.
Мне интересно, должен ли я попытаться построить стратегию frequency
самостоятельно из существующих стратегий Гипотезы, или сама идиома не стоит переводить, и я должен просто позволить структуре генерировать действительные и недействительные примеры одинаково?
Что у меня сейчас есть:
from hypothesis import strategies as st
@st.composite
def make_indent_(draw, val, size):
"""
Indent `val` by `size` using either space or tab.
Will sometimes randomly ignore `size` param.
"""
whitespace_char = st.text(' \t', min_size=1, max_size=1)
trailing = draw(st.text(draw(whitespace_char)))
indent = draw(st.one_of(
st.text(draw(whitespace_char), min_size=size, max_size=size),
st.text(draw(whitespace_char)),
))
return ''.join([indent, val, trailing])
Если я сгенерирую несколько примеров в оболочке, то это, похоже, будет делать именно то, что, как я думаю, должно быть.
Но я впервые использую гипотезу или тестирование на основе свойств, и мне интересно, теряю ли я что-то жизненно важное, заменив дистрибутив frequency
простым one_of
?