Py.test - Сеансовая настройка - PullRequest
1 голос
/ 07 ноября 2011

Я пытаюсь построить хорошую базу вокруг py.test

Некоторые из наших тестов нуждаются в определенных тестовых данных для работы.

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

Вот пример того, как это может выглядеть сегодня:

def test_something(self, some_data):
    # some_data is unused in the test

Я хотел бы сделать что-то вроде этого:

@uses_some_data
def test_something(self):
    # The data is loaded when the test is run

Хотя я не понял, как это сделать правильно.

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

Моя первая идея состояла в том, чтобы по-прежнему использовать funcargs, но вместо того, чтобы позволить тесту иметь funcarg, мы позволяем декоратору запрашивать funcarg для функции, в основном скрывая уродство.Проблема в том, что мне нужен объект py.test для запроса funcarg.
Есть ли какой-нибудь способ, которым я могу получить такой объект, или это неправильный подход все вместе?

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

Ответы [ 2 ]

1 голос
/ 08 ноября 2011

Поиграв, я обнаружил, что это работает:

def pytest_funcarg__some_data(request):
    def create():
        # Load the test data here
        print 'Test data loaded'

    return request.cached_setup(
        setup=create,
        scope='session',
        extrakey='some_data'
    )

def uses_some_data(func):
    # The funcarg is actually requested here
    def wrapper(self, some_data):
        return func
    return wrapper

class TestSomething(object):
    @uses_some_data
    def test_something(self):
        # "Some data" is now available
        pass
1 голос
/ 07 ноября 2011

Вот кое-что, что может работать как есть, и если нет, то, надеюсь, укажет вам правильное направление.

class TestData(object):
    def __getattr__(self, name):
        if name not in ('data1', 'data2', 'data3'):
            raise AttributeError("TestData has no %s" % name)
        if name == 'data1':
            result = self._generate_data('data1')
            setattr(self.__class__, name, result)
        elif name == 'data2':
            result = self._generate_data('data2')
            setattr(self.__class__, name, result)
        elif name == 'data3':
            result = self._generate_data('data3')
            setattr(self.__class__, name, result)
        return result
    def _generate_data(self, data_name):
        return data_name * int(data_name[-1])

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

class uses_some_data(object):
    def __init__(self, func):
        self.func = func
    def __call__(self, *args, **kwargs):
        global test_data
        test_data = TestData()
        return self.func(*args, **kwargs)

Простой декоратор для установки глобальной привязки имени для test_data.На самом деле, эта версия декоратора настолько проста, что может быть легко заменена привязкой имени уровня модуля test_data = TestData().

@uses_some_data
def testing_test():
    print(test_data.data2)

и тестовой функцией.

Если вы неНе похоже на глобальный уровень test_data, вы можете стать более привлекательным с декоратором и присвоить test_data самой функции:

class uses_some_data(object):
    def __init__(self, func):
        self.func = func
    def __call__(self, *args, **kwargs):
        self.func.test_data = TestData()
        return self.func(*args, **kwargs)

В этом случае убедитесь, что ваши функции тестирования ссылаются на себя

@uses_some_data
def testing_test():
    print(testing_test.test_data.data2)
...