Пропуск всех модульных тестов, кроме одного в Python, с использованием декораторов и метаклассов

Я пишу модульные тесты для MCU, который передает команды через порт USB и проверяет их ответ. Если один модульный тест не проходит, мне имеет смысл выполнить некоторую отладку в MCU. Поэтому я хотел бы отключить все модульные тесты, кроме того, который я хотел бы отлаживать на стороне MCU, потому что, если я где-то установлю точку останова, он может быть запущен другим модульным тестом с другими командами.

Я зашел в документацию python и нашел этот код, который является декоратором, который пропускает все модульные тесты, у которых нет атрибута.

def skipUnlessHasattr(obj, attr):
    if hasattr(obj, attr):
        return lambda func: func
return unittest.skip("{!r} doesn't have {!r}".format(obj, attr))

Чтобы упростить задачу, я удалил аргумент attr и статически изменил его на «StepDebug», который является атрибутом, который я хочу установить только в одном модульном тесте для его отладки.

Итак, следующий шаг для меня - автоматически применить это ко всем моим методам класса. Прочитав в сети, я нашел следующий код, который использует метакласс для украшения всех методов указанным выше декоратором. https://stackoverflow.com/a/6308016/3257551

def decorating_meta(decorator):
class DecoratingMetaclass(type):
    def __new__(self, class_name, bases, namespace):
        for key, value in list(namespace.items()):
            if callable(value):
                namespace[key] = decorator(value)
        return type.__new__(self, class_name, bases, namespace)

return DecoratingMetaclass

Итак, мой минимальный рабочий пример:

import unittest

def decorating_meta(decorator):
    class DecoratingMetaclass(type):
        def __new__(self, class_name, bases, namespace):
            for key, value in list(namespace.items()):
                if callable(value):
                    namespace[key] = decorator(value)
            return type.__new__(self, class_name, bases, namespace)

    return DecoratingMetaclass

def skipUnlessHasattr(obj):
    if hasattr(obj, 'StepDebug'):
        return lambda func : func
    return unittest.skip("{!r} doesn't have {!r}".format(obj, 'StepDebug'))

class Foo(unittest.TestCase):
    __metaclass__ = decorating_meta(skipUnlessHasattr)
    def test_Sth(self):
        self.assertTrue(False)

if __name__ == '__main__':
    unittest.main()

и ошибка, которую я получаю:

AttributeError: 'Foo' object has no attribute '__name__'

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

Может кто-нибудь помочь?


person Satrapes    schedule 08.05.2015    source источник
comment
Извините, я не могу понять, почему вы не можете использовать что-то вроде @unittest.skipUnlessHasattr("StepDebug") до того, как ваше объявление теста класса действительно декорирует весь метод. Кроме того, вы можете определить собственный декоратор как def myskip(): return unittest.skipUnlessHasattr("StepDebug").   -  person Michele d'Amico    schedule 08.05.2015
comment
Если я правильно понимаю ваш вопрос, я не хочу просто добавлять декоратор перед каждым методом test_ *, потому что у меня будет много модульных тестов, и я не хочу добавлять его каждый раз вручную, если есть возможность делать это автоматически.   -  person Satrapes    schedule 08.05.2015
comment
Я не уверен, но, возможно, @unittest.skipUnlessHasattr() тоже будет работать как декоратор классов. Я уверен, что вы можете применить @skip docorator классу, но неясно, действительно ли это и для skipUnlessHasattr().   -  person Michele d'Amico    schedule 08.05.2015
comment
Я, вероятно, что-то неправильно понимаю, но почему бы вам просто не запустить только тест, который вы хотите отладить, а не весь набор?   -  person Noufal Ibrahim    schedule 09.05.2015
comment
Я не сделал этого, потому что думал, что тогда мне придется комментировать / раскомментировать много кода. Моя идея заключалась в том, что всякий раз, когда я хочу что-то отладить, просто включите тест, который не удался.   -  person Satrapes    schedule 10.05.2015


Ответы (2)


https://stackoverflow.com/a/44804070/1587329 использует декораторы, инициализируя их через параметры среды.

MCU = os.getenv('MCU', False)

и декорирование тестовых классов и / или методов, которые должны быть исключены через f.ex.

@unittest.skipIf(MCU)

это можно назвать

MCU=1 python # test file etc

Единственное, что здесь не так важно, это то, что все остальные тесты выводятся не как пропущенные, а как успешные.

Пропущенные тесты помечаются как s.

person serv-inc    schedule 15.08.2017
comment
Я тоже этим занимаюсь. В Bash и многих других оболочках не забудьте export переменную среды, чтобы Python мог ее увидеть. - person Leo; 12.10.2020

Хорошо, я нашел способ получить нужную мне функциональность. Я изменил декоратор на:

def skipUnlessHasattr(obj):
    if hasattr(obj, 'StepDebug'):
        def decorated(*a, **kw):
            return obj(*a, **kw)
        return decorated
    else:
        def decorated(*a, **kw):
            return unittest.skip("{!r} doesn't have {!r}".format(obj, 'StepDebug'))
        return decorated

Теперь все тесты пропущены, кроме тех, для которых я добавил атрибут StepDebug.

Единственное, что здесь не так важно, это то, что все остальные тесты выводятся не как пропущенные, а как успешные.

..F..
======================================================================
FAIL: test_ddd (__main__.Foo)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "./Documents/programs/Python/mwe.py", line 23, in     decorated
    return obj(*a, **kw)
  File "./Documents/programs/Python/mwe.py", line 39, in     test_ddd
    self.assertTrue(False)
AssertionError: False is not true

----------------------------------------------------------------------
Ran 5 tests in 0.014s

FAILED (failures=1)

P.S. Почему при копировании вывода после отступа в 4 пробела он не попадает в блок кода? Я тоже пробовал 8 пробелов, и это не сработало. В конце концов я добавил по 4 пробела в каждую строку. Есть ли способ поумнее?

person Satrapes    schedule 09.05.2015