Вопрос №55206 от пользователя Nmbrtw в уроке «Подготовка данных», курс «Python: Автоматическое тестирование»

Nmbrtw

Как-то мало в этом модуле уроков обсуждений, хотя они намного сложнее (и возможно важнее) предыдущих. Поэтому буду задавать глупые вопросы, надеюсь ответы на них кому-то после меня пригодятся.

В документации пайтеста в фикстурах есть такие конструкции:

import pytest

@pytest.fixture
def a():
    return []

@pytest.fixture
def b():
   return 'b'

@pytest.fixture
def c():
    return 'c'

test_append_b(a, b):
    assert a.append(b) == ['b']

test_append_c(a,c):
    assert a.append(c) == ['c']

верно я понимаю, что каждый раз, когда тест вызывает фикстуру, то внутри ее пересоздается все заново, и так мы решаем вопрос с мутабельными объектами и в целом с зависимостью тестов друг от друга?

И почему бы тогда не порекомендовать все последующие практики решать через такие конструкции? Чтобы хотя бы руку набить и привыкнуть

4 0

Aleksei Pirogov

Обсуждений мало, потому что курс только-только опубликовали и его ещё предстоит отполировать! Заодно и обсуждения появятся :)

когда тест вызывает фикстуру, то внутри ее пересоздается все заново, и так мы решаем вопрос с мутабельными объектами и в целом с зависимостью тестов друг от друга?

Тест не вызывает фикстуру, они вызываются внутри pytest, как только среди имён аргументов того или иного теста встретится нужное имя. Но суть вы уловили правильно: любая функция, помеченная как фикстура, вызывается для каждого, зависящего от неё теста, заново. И да, таким образом обеспечивается независимость тестов от окружения. Однако, так ведут себя функции, которые декорированы pytest.fixture без параметров.

А вот используя параметры, можно заставить каждую фикстуру породить несколько значений, после чего pytest будет вызвать каждый зависимый тест для каждого отдельного значения:

@pytest.fixture(
    params=[
        'foo',
        42,
        object(),
        (1, 2, 3),
        [None],
    ],
)
def truthful():
    return pytest.param
    #      ^ так можно получить доступ к параметру 


def test_truth(truthful):  # этот тест будет вызван пять раз
    assert truthful

Кроме того, можно задать и область видимости фикстуры. Скажем, описать фикстуру, которая создаёт временную директорию, единоразово распаковывает в неё файлы из заготовленного архива и делает доступной для всех тестов в модуле, а удаляет директорию только после завершения всех тестов:

@pytest.fixture(scope='module')
def sandbox():
    with tempfile.TemporaryDirectory() as tmp:
        yield Path(tmp)
        # ^ директория отправляется как значение фикстуры
    # к этому моменту директория будет удалена


@pytest.fixture(scope='module')
def data_files(sandbox):
    with zipfile.ZipFile(
        Path(__file__).parent / 'data' / 'examples.zip',
    ) as z:
        z.extractall(sandbox)
        return [
            sandbox / name
            for name in z.namelist()
        ]


def test_foo(data_files):
    assert all(p.exists() for p in data_files)

Словом, возможностей у pytest предостаточно!

И вот тут мы как раз подходим к

И почему бы тогда не порекомендовать все последующие практики решать через такие конструкции?

Возможностей у pytest слишком много, чтобы был смысл подробно расписывать сколько-нибудь приличную их часть. Поэтому в курсе показаны только самые основы. За подробностями же лучше всего обращаться к официальной документации — только так вы будете получать максимально актуальную и полную информацию.

1

Ivan Al

Ребята, наверное стоит более ясно сформулировать задание, а в теории подробнее рассмотреть, на какие случаи стоит писать тесты. Без просмотра решения учителя совершенно непонятно было, каких и сколько тестов нужно написать. В предыдущих заданиях все было понятно по примеру выдачи REPL, а тут оказалось нужно делать все иначе.

И при теории с фикстурами и общими данными для группы тестов в решении это не используется никак =(

3

Иван Рябкин

Aleksei Pirogov, попробовал запустить ваш код под первым спойлеров (фикстуры с использованием параметров). И там функция def test_truth получает в качестве аргумента <function param at 0x7f7fbfc204c0> (5 раз разные) А вы же наверное имели в виду что в эту функцию в качестве аргумента передаются именно значения параметров? Вроде нашел в интернете, что это делается так: def truthful(request): return request.param Тогда, например, если поставить в параметры что-то со значением False, то тест с этим параметром не пройдет.

0

Aleksei Pirogov

Иван Рябкин, да, всё верно, это я напутал: pytest.param про другое :) А вы нашли правильный вариант: функция-фикстура должна иметь принимать один аргумент и обращаться к его атрибуту .param.

1

Используйте Хекслет по максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Даю согласие на обработку персональных данных, соглашаюсь с «Политикой конфиденциальности» и «Условиями оказания услуг»

Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Фронтенд-разработчик
Профессия
Разработка фронтенд-компонентов веб-приложений
18 мая 10 месяцев
Иконка программы Python-разработчик
Профессия
Разработка веб-приложений на Django
18 мая 10 месяцев
Иконка программы PHP-разработчик
Профессия
Разработка веб-приложений на Laravel
18 мая 10 месяцев
Иконка программы Node.js-разработчик
Профессия
Разработка бэкенд-компонентов веб-приложений
18 мая 10 месяцев
Иконка программы Fullstack-разработчик
Профессия
Новый
Разработка фронтенд и бэкенд компонентов веб-приложений
18 мая 16 месяцев
Иконка программы Верстальщик
Профессия
Вёрстка с использованием последних стандартов CSS
в любое время 5 месяцев
Иконка программы Java-разработчик
Профессия
Разработка приложений на языке Java
18 мая 10 месяцев
Иконка программы Разработчик на Ruby on Rails
Профессия
Создает веб-приложения со скоростью света
18 мая 5 месяцев