Гипотезный эквивалент генератора частоты QuickCheck? - PullRequest
4 голосов
/ 23 марта 2019

В качестве учебного проекта я перевожу некоторый код на 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?

1 Ответ

4 голосов
/ 25 марта 2019

Насколько я понимаю, вы правильно поняли цель использования frequency здесь. Он используется для разрешения случайного отступа неправильного размера вместо того, чтобы (1) генерировать только отступы правильного размера, которые никогда не будут проверять неверные размеры отступов; или (2) генерировать отступы произвольного размера, которые будут проверять плохие отступы снова и снова, но генерировать только часть случаев с хорошими отступами для проверки других аспектов кода.

Теперь соотношение хороших и (потенциально) плохих размеров отступа 5: 1, вероятно, совершенно произвольно, и трудно понять, был бы лучший выбор 1: 1 или 10: 1, не видя деталей того, что тестируется. ,

К счастью, в связи с переносом этого на hypothesis ответ на Имеет стратегию, которая не делает одинакового выбора между различными стратегиями включает удаленный комментарий:

Гипотеза на самом деле не поддерживает специфичные для пользователя вероятности - мы начинаем с равномерного распределения, но смещаем его на основе охвата наблюдаемыми данными. [...] - Зак Хатфилд-Доддс 15 апреля 1818 в 3: 43

Это говорит о том, что пакет «гипотезы» автоматически корректирует весовые коэффициенты при использовании one_of для увеличения охвата, а это означает, что он может автоматически повысить вес кейса с правильным размером в вашей реализации make_indent_, что делает его своего рода автоматической версией frequency.

...