py.test: как получить имя текущего теста из метода установки?

Я использую py.test и задаюсь вопросом, можно ли/как получить имя текущего выполняемого теста в методе setup, который вызывается перед запуском каждого теста. Рассмотрим этот код:

class TestSomething(object):

    def setup(self):
        test_name = ...

    def teardown(self):
        pass

    def test_the_power(self):
        assert "foo" != "bar"

    def test_something_else(self):
        assert True

Прямо перед выполнением TestSomething.test_the_power я хотел бы иметь доступ к этому имени в setup, как указано в коде, через test_name = ..., чтобы test_name == "TestSomething.test_the_power".

На самом деле, в setup я выделяю какой-то ресурс для каждого теста. В конце концов, глядя на ресурсы, созданные различными модульными тестами, я хотел бы видеть, какой из них был создан каким тестом. Лучше всего было бы просто использовать тестовое имя при создании ресурса.


person Dr. Jan-Philip Gehrcke    schedule 18.07.2013    source источник
comment
Как насчет этого unittest.TestCase.id()   -  person Nam G VU    schedule 19.12.2018
comment
Работает ли это с тестами в стиле pytest (то есть автономными функциями, а не методами класса, наследуемого от TestCase)?   -  person Adam Parkin    schedule 08.02.2019


Ответы (7)


Вы также можете сделать это с помощью Запросить Fixture следующим образом:

def test_name1(request):
    testname = request.node.name
    assert testname == 'test_name1'
person danielfrg    schedule 11.01.2016
comment
Это ответ общего назначения, в равной степени применимый как к тестовым функциям, , так и к методам тестирования. В то время как документация py.test обычно впечатляет, его документация для фикстуры request необычайно ужасна. Атрибут request.node задокументирован только как базовый узел коллекции (зависит от текущей области запроса). Вот и все. Я абсолютно никогда не нашел бы это — и сомневаюсь, что кто-то другой тоже нашел бы это. Браво, лягушонок Даниэль! - person Cecil Curry; 23.05.2016
comment
Обратите внимание, однако, что когда тестовая функция была параметризована, request.node.name содержит уникальное имя с параметрами, например. test_name[param-other_param]. Поэтому безопаснее всегда использовать request.node.originalname, что обеспечивает неизменное исходное имя функции. Также обратите внимание, что это доступно, начиная с py.test 3.0. - person julen; 12.12.2016
comment
В вашей ссылке нет упоминания о приборе запроса. - person OrangeDog; 04.05.2018
comment
@julen, но если тест не параметризован, originalname равно None - person OrangeDog; 04.05.2018
comment
Note however when the test function has been parametrized, request.node.name contains the unique name with parameters, e.g. test_name[param-other_param]. Для меня это то, что я хочу, потому что мне нужно уникальное имя выходного файла. - person Polv; 17.07.2018
comment
Вы также можете получить имя модуля с помощью request.module.__name__. - person Colin Schoen; 18.01.2019
comment
Просто отметим, что документация теперь намного понятнее по использованию этого: docs.pytest.org/en/documentation-restructure/how-to/ - person robo; 25.03.2021

Вы также можете использовать переменную среды PYTEST_CURRENT_TEST, установленную pytest для каждого теста.

переменная среды PYTEST_CURRENT_TEST

Чтобы получить только имя теста:

os.environ.get('PYTEST_CURRENT_TEST').split(':')[-1].split(' ')[0]
person Joao Coelho    schedule 21.08.2018
comment
Вау, это должен быть самый простой ответ, и его следует принять - person Nam G VU; 19.12.2018
comment
Только что протестирован с pytest 4.0.2, и он работает. Вы также можете добавить .strip('[]'), чтобы удалить больше посторонней информации. PS: вам нужно добавить код внутри тестового примера. - person Joao Coelho; 20.12.2018
comment
Я имею в виду, что env varia le не определяется. Нужно ли нам где-то настраивать pytest для этого? - person Nam G VU; 20.12.2018
comment
О, теперь я вижу, что это из метода setup.. не уверен, что эта env var определена в этот момент. в качестве альтернативы можно просто запустить этот фрагмент кода (или вызвать его как отдельную функцию) в начале теста. - person Joao Coelho; 21.12.2018
comment
Большое спасибо, отличные советы, я получаю имя теста на свой conftest.py ... еще раз спасибо за ссылку и трюк. - person Buddhika Chaturanga; 21.01.2019
comment
Люблю этот ответ! - person laike9m; 22.07.2020
comment
Это лучший ответ, который я видел по этому конкретному вопросу, и я искал его как минимум несколько часов. Благодарим Вас за отправку исправленного варианта. - person MistaWizard; 01.12.2020
comment
Примечание. Содержимое PYTEST_CURRENT_TEST предназначено для чтения человеком, а фактический формат может быть изменен между выпусками (даже исправлениями ошибок), поэтому на него не следует полагаться при написании сценариев или автоматизации. - person zowers; 16.03.2021

Методы setup и teardown кажутся устаревшими методами поддержки тестов, написанных для других фреймворков, например. нос. Собственные методы pytest называются setup_method, а также teardown_method, которые получают текущий исполняемый тестовый метод в качестве аргумента. Следовательно, то, чего я хочу достичь, можно записать так:

class TestSomething(object):

    def setup_method(self, method):
        print "\n%s:%s" % (type(self).__name__, method.__name__)

    def teardown_method(self, method):
        pass

    def test_the_power(self):
        assert "foo" != "bar"

    def test_something_else(self):
        assert True

Выход py.test -s тогда:

============================= test session starts ==============================
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
plugins: cov
collected 2 items 

test_pytest.py 
TestSomething:test_the_power
.
TestSomething:test_something_else
.

=========================== 2 passed in 0.03 seconds ===========================
person Dr. Jan-Philip Gehrcke    schedule 19.07.2013

У вас может быть несколько тестов, и в этом случае...

test_names = [n for n in dir(self) if n.startswith('test_')]

... предоставит вам все функции и переменные экземпляра, которые начинаются с "test_" в self. Пока у вас нет переменных с именем «test_something», это будет работать.

Вы также можете определить метод setup_method(self, method) вместо setup(self), который будет вызываться перед каждым вызовом тестового метода. Используя это, вы просто получаете каждый метод в качестве параметра. См.: http://pytest.org/latest/xunit_setup.html.

person ejk314    schedule 18.07.2013
comment
Все методы, представляющие тесты py.test, начинаются с test. Здесь мне нужен py.test API, потому что py.test заранее собрал все тесты (в основном так, как вы предложили здесь) и уже знает, какой тест нужно запустить сейчас. Я просто не знаю, какой вопрос задать py.test :-) - person Dr. Jan-Philip Gehrcke; 18.07.2013
comment
Комментарий после вашего редактирования: я не хочу просто иметь список всех методов, начинающихся с test_. Из этого списка мне нужно одно имя/метод теста, выполняемого прямо сейчас. И это могут сказать только внутренности py.test. - person Dr. Jan-Philip Gehrcke; 18.07.2013
comment
Я думаю, вы хотите setup_method вместо setup - person ejk314; 18.07.2013
comment
Я хочу setup, потому что это то, что py.test вызывает для инициализации каждого теста. - person Dr. Jan-Philip Gehrcke; 18.07.2013
comment
Спасибо, это был определенно правильный указатель. Я уже давно использую py.test с setup и teardown, не понимая, что эти методы более или менее поддерживаются только по устаревшим причинам (это правильно, не так ли?). Чтобы ответить на вопрос с примером кода, я представил свой собственный ответ. Надеюсь, с тобой все в порядке. - person Dr. Jan-Philip Gehrcke; 19.07.2013

Вы можете дать модуль проверки попробовать.

import inspect

def foo():
    print "My name is: ", inspect.stack()[0][3]


foo()

Выход: My name is: foo

person Robert Caspary    schedule 18.07.2013
comment
Вызванный из метода setup, он, очевидно, возвращает setup. - person Dr. Jan-Philip Gehrcke; 18.07.2013

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

def get_current_test():
    full_name = os.environ.get('PYTEST_CURRENT_TEST').split(' ')[0]
    test_file = full_name.split("::")[0].split('/')[-1].split('.py')[0]
    test_name = full_name.split("::")[1]

    return full_name, test_file, test_name
person matt3o    schedule 30.04.2020

Попробуйте type(self).__name__ возможно?

person kindall    schedule 18.07.2013
comment
В моем примере это даст только TestSomething. Я в основном после второй части имени :) - person Dr. Jan-Philip Gehrcke; 18.07.2013