Объявите связь между двумя аргументами, сгенерированными гипотезой - PullRequest
1 голос
/ 04 июля 2019

Я использую гипотезу для тестирования, и я хотел установить связь между двумя аргументами теста. Я знаю о assume, но это кажется довольно расточительным, когда я заранее знаю ограничения.

Вот минимальный пример:

from datetime import date

import pytest
from hypothesis import given, assume, strategies as st


def get_daterange_filter(start, end):
    """`start` and `end` are dates of the format: YYYYMMDD"""
    if int(start) > int(end):
        raise ValueError(f"{start} comes after {end}")
    else:
        pass


dt_strategy = st.dates(min_value=date(2019, 4, 1),
                       max_value=date(2019, 7, 31))


@given(dt_strategy, dt_strategy)
def test_daterange_filter(dt1, dt2):
    assume(dt1 > dt2)
    start, end = dt1.strftime("%Y%m%d"), dt2.strftime("%Y%m%d")
    with pytest.raises(ValueError):
        get_daterange_filter(start, end)

Сводная статистика по вышеуказанным отчетам следующая:

hypo.py::test_daterange_filter:

  - 100 passing examples, 0 failing examples, 68 invalid examples
  - Typical runtimes: 0-1 ms
  - Fraction of time spent in data generation: ~ 47%
  - Stopped because settings.max_examples=100

Это довольно много напрасных попыток. Это очень простой случай, но в типичном проекте с большими объемами данных я могу предвидеть множество таких сценариев. Поэтому мне было интересно, есть ли простой способ выдвинуть гипотезу о том, что два аргумента удовлетворяют определенной взаимосвязи (в данном случае один больше другого). Я не смог ничего найти в документах.

1 Ответ

1 голос
/ 05 июля 2019

Если вам нужны взаимозависимые стратегии, используйте совместное использование стратегий:

dates = st.shared(st.dates(min_value=date(2019, 4, 1), max_value=date(2019, 7, 31)))

@st.composite
def later_dates(draw):
    return draw(st.dates(min_value=draw(dates)))
    # or, if you need the strict inequality for passing
    # the test in its given form, add a day to min_value:
    # return draw(st.dates(min_value=draw(dates) + timedelta(days=1)))


@given(start=later_dates(), end=dates)
def test_daterange_filter(start, end):
    fstart, fend = start.strftime("%Y%m%d"), end.strftime("%Y%m%d")
    with pytest.raises(ValueError):
        get_daterange_filter(fstart, fend)

Запуск большего количества примеров с записанным временем:

...
collected 2 items

test_spam.py::test_daterange_filter PASSED
test_spam.py::test_daterange_filter_shared_date_strategy PASSED
======================================== Hypothesis Statistics =========================================

test_spam.py::test_daterange_filter:

  - 10000 passing examples, 0 failing examples, 10050 invalid examples
  - Typical runtimes: < 1ms
  - Fraction of time spent in data generation: ~ 44%
  - Stopped because settings.max_examples=10000

test_spam.py::test_daterange_filter_shared_date_strategy:

  - 10000 passing examples, 0 failing examples, 0 invalid examples
  - Typical runtimes: < 1ms
  - Fraction of time spent in data generation: ~ 50%
  - Stopped because settings.max_examples=10000

======================================== slowest test durations ========================================
12.55s call     test_spam.py::test_daterange_filter
6.27s call     test_spam.py::test_daterange_filter_shared_date_strategy

(0.00 durations hidden.  Use -vv to show these durations.)
====================================== 2 passed in 18.86 seconds =======================================
...