Подтвердить что ты не робот

Передать параметр в функцию прибора

Я использую py.test, чтобы протестировать некоторый DLL-код, заключенный в класс MyTester класса python. Для проверки цели мне нужно записать некоторые тестовые данные во время тестов и сделать больше обработки впоследствии. Поскольку у меня много тестовых файлов _..., я хочу повторно использовать создание объекта тестера (экземпляр MyTester) для большинства моих тестов.

Поскольку объектом тестера является тот, который получил ссылки на переменные и функции DLL, мне нужно передать список переменных DLL в объект тестера для каждого из тестовых файлов (переменные, которые будут регистрироваться, одинаковы для test _... file). Содержимое списка должно использоваться для регистрации указанных данных.

Моя идея - сделать это как-то так:

import pytest

class MyTester():
    def __init__(self, arg = ["var0", "var1"]):
        self.arg = arg
        # self.use_arg_to_init_logging_part()

    def dothis(self):
        print "this"

    def dothat(self):
        print "that"

# located in conftest.py (because other test will reuse it)

@pytest.fixture()
def tester(request):
    """ create tester object """
    # how to use the list below for arg?
    _tester = MyTester()
    return _tester

# located in test_...py

# @pytest.mark.usefixtures("tester") 
class TestIt():

    # def __init__(self):
    #     self.args_for_tester = ["var1", "var2"]
    #     # how to pass this list to the tester fixture?

    def test_tc1(self, tester):
       tester.dothis()
       assert 0 # for demo purpose

    def test_tc2(self, tester):
       tester.dothat()
       assert 0 # for demo purpose

Можно ли достичь этого так или есть даже более элегантный способ?

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

Я знаю, что могу сделать что-то вроде этого: (из документов)

@pytest.fixture(scope="module", params=["merlinux.eu", "mail.python.org"])

Но мне нужно параметризацию непосредственно в тестовом модуле. Возможно ли получить доступ к атрибуту params прибора из тестового модуля?

4b9b3361

Ответ 1

У меня была аналогичная проблема - у меня есть устройство с именем test_package, и позже я захотел передать необязательный аргумент этому инструменту при его запуске в конкретных тестах. Например:

@pytest.fixture()
def test_package(request, version='1.0'):
    ...
    request.addfinalizer(fin)
    ...
    return package

(Для этих целей не имеет значения, что делает прибор или какой тип объекта возвращается package).

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

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

@pytest.fixture()
def test_package(request):
    def make_test_package(version='1.0'):
        ...
        request.addfinalizer(fin)
        ...
        return test_package

    return make_test_package

Теперь я могу использовать это в своей тестовой функции, например:

def test_install_package(test_package):
    package = test_package(version='1.1')
    ...
    assert ...

и т.д.

Решение об попытке OP было направлено в правильном направлении, и, как предлагает @hpk42 , MyTester.__init__ может просто сохранить ссылку на запрос, например:

class MyTester(object):
    def __init__(self, request, arg=["var0", "var1"]):
        self.request = request
        self.arg = arg
        # self.use_arg_to_init_logging_part()

    def dothis(self):
        print "this"

    def dothat(self):
        print "that"

Затем используйте это, чтобы реализовать приспособление вроде:

@pytest.fixture()
def tester(request):
    """ create tester object """
    # how to use the list below for arg?
    _tester = MyTester(request)
    return _tester

При желании класс MyTester может быть реструктурирован бит, чтобы его атрибут .args мог быть обновлен после его создания, чтобы настроить поведение для отдельных тестов.

Ответ 2

Это фактически поддерживается в py.test через косвенную параметризацию.

В вашем случае у вас будет:

@pytest.fixture
def tester(request):
    """Create tester object"""
    return MyTester(request.param)


class TestIt:
    @pytest.mark.parametrize('tester', [['var1', 'var2']], indirect=True)
    def test_tc1(self, tester):
       tester.dothis()
       assert 1

Ответ 3

Вы можете получить доступ к запрашивающему модулю/классу/функции из функций привязки (и, следовательно, от вашего класса Tester), см. взаимодействие с запросом тестового контекста с помощью функции привязки. Таким образом, вы можете объявить некоторые параметры в классе или модуле, и прибор тестера может его поднять.

Ответ 4

Чтобы немного улучшить имиричный ответ: еще один элегантный способ решить эту проблему - создать " фиксаторы параметров". Я лично предпочитаю это indirect функции pytest. Эта функция доступна в pytest_cases, и оригинальная идея была предложена Sup3rGeo.

import pytest
from pytest_cases import param_fixture

# create a single parameter fixture
var = param_fixture("var", [['var1', 'var2']], ids=str)

@pytest.fixture
def tester(var):
    """Create tester object"""
    return MyTester(var)

class TestIt:
    def test_tc1(self, tester):
       tester.dothis()
       assert 1

Обратите внимание, что pytest-cases также предоставляет @pytest_fixture_plus который позволяет вам использовать метки параметризации для ваших приборов, и @cases_data которые позволяют вам @cases_data параметры из функций в отдельном модуле. Смотрите документ для деталей. Я, кстати, автор;)