Получить название текущего теста в настройке, используя нос

В настоящее время я пишу некоторые функциональные тесты, используя нос. Библиотека, которую я тестирую, управляет структурой каталогов.

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

Теперь у меня есть два дополнительных требования:

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

Оба эти требования могут быть решены путем создания новой копии с другим именем для каждого выполняемого теста. По этой причине я хотел бы получить доступ к названию теста, который в настоящее время выполняется в setup функция, так что я могу назвать копию соответствующим образом. Есть ли способ добиться этого?

Пример иллюстративного кода:

def setup_func(test_name):
    print "Setup of " + test_name

def teardown_func(test_name):
    print "Teardown of " + test_name

@with_setup(setup_func, teardown_func)
def test_one():
    pass

@with_setup(setup_func, teardown_func)
def test_two():
    pass

Ожидаемый результат:

Setup of test_one
Teardown of test_one
Setup of test_two
Teardown of test_two

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

3 ответа

Решение

У меня есть решение, которое работает для тестовых функций, используя собственный декоратор:

def with_named_setup(setup=None, teardown=None):
    def wrap(f):
        return with_setup(
            lambda: setup(f.__name__) if (setup is not None) else None, 
            lambda: teardown(f.__name__) if (teardown is not None) else None)(f)
    return wrap

@with_named_setup(setup_func, teardown_func)
def test_one():
    pass

@with_named_setup(setup_func, teardown_func)
def test_two():
    pass

Это использует существующие with_setup декоратор, но связывает имя оформленной функции с setup а также teardown функции передаются в качестве параметров.

Звучит как self._testMethodName или self.id() должен работать для вас. Это свойство и метод на unittest.TestCase учебный класс. Например:

from django.test import TestCase


class MyTestCase(TestCase):
    def setUp(self):
        print self._testMethodName
        print self.id()

    def test_one(self):
        self.assertIsNone(1)

    def test_two(self):
        self.assertIsNone(2)

печатает:

...
AssertionError: 1 is not None
-------------------- >> begin captured stdout << ---------------------
test_one
path.MyTestCase.test_one

--------------------- >> end captured stdout << ----------------------
...
AssertionError: 2 is not None
-------------------- >> begin captured stdout << ---------------------
test_two
path.MyTestCase.test_two

--------------------- >> end captured stdout << ----------------------

Также см:

Надеюсь, это поможет.

В случае, если вы не хотите подкласс unittest.TestCase или используйте собственный декоратор (как объяснено в других ответах), вы можете получить информацию, копаясь в стеке вызовов:

import inspect

def get_current_case():
    '''
    Get information about the currently running test case.

    Returns the fully qualified name of the current test function
    when called from within a test method, test function, setup or 
    teardown.

    Raises ``RuntimeError`` if the current test case could not be
    determined.

    Tested on Python 2.7 and 3.3 - 3.6 with nose 1.3.7.
    '''
    for frame_info in inspect.stack():
        if frame_info[1].endswith('unittest/case.py'):
            return frame_info[0].f_locals['self'].id()
    raise RuntimeError('Could not determine test case')
Другие вопросы по тегам