Как загрузить тесты из одних файлов, а не из других?

Вопрос или проблема

Я хочу запустить набор модульных тестов в папке tests. Основной код:

suite = unittest.defaultTestLoader.discover('tests')

Я хочу запустить только некоторые из этих тестов, например test_e1, если файл e1.py присутствует, test_e5, если e5.py присутствует, но не test_e2 и test_e11 (поскольку файлы e2.py и e11.py отсутствуют).

Я попробовал аргумент pattern функции discoverer(), который по умолчанию равен test_*.py, но он не предоставляет достаточного контроля для того, что мне нужно (см. Как сопоставить конкретные файлы с шаблоном оболочки в модульном тесте обнаружения?).

Один из ответов в этой теме предлагает найти эти тесты с помощью unittest.TestLoader().loadTestsFromNames, так что я попробовал следующий код:

    file_list = []

    for some_file in some_file_list:
        full_filepath = os.path.join(some_dir, some_file)
        if not os.path.exists(full_filepath):
            continue
        file_list.append("tests/test_%s.TestDocs" % some_file)

    suite = unittest.TestLoader().loadTestsFromNames(file_list)
    print(suite)

Имя TestDocs – это имя класса, который наследуется от модульного теста:

class TestDocs(unittest.TestCase):

Но это показывает список проваленных тестов, таких как:

<unittest.suite.TestSuite tests=[<unittest.loader._FailedTest testMethod=tests/test_>]>

Как я могу запустить тесты только для определенного набора файлов?

Вы передаете гибридные имена файлов/объектов в loadTestsFromNames. Уберите tests из имени и убедитесь, что tests присутствует в вашем модульном поисковом пути, либо путем

  1. Изменения sys.path перед вызовом метода, либо
  2. Добавления tests в переменную окружения PYTHONPATH перед запуском ваших тестов.

Структура файловой системы, используемая для воспроизведения вашего кода

Я создал на своей системе следующую структуру:

test_project
  |- tests
  |    |- __init__.py
  |    |- test_e1.py
  |    |- test_e2.py
  |- production
  |    |- e1.py
  |- run_tests.py

В папке tests находятся:

  • тестовые файлы test_e1.py, test_e2.py
  • файл __init__.py (tests должен быть пакетом для правильного выполнения)

Папка production содержит файл e1.py, но не содержит файл e2.py, так что методы тестов из файла test_e2.py не должны выполняться.

Файл run_tests.py с изменениями

Я сохранил ваш код (изменив одну инструкцию и добавив инструкцию для выполнения тестов) в файл run_tests.py:

import unittest
import os

some_dir = "/path/to/production"
some_file_list = ["e1.py", "e2.py"]

file_list = []

for some_file in some_file_list:
    full_filepath = os.path.join(some_dir, some_file)
    if not os.path.exists(full_filepath):
        continue
    # file_list.append("tests/test_%s.TestDocs" % some_file)
    file_list.append("tests.test_%s.TestDocs" % some_file.split('.')[0])

suite = unittest.TestLoader().loadTestsFromNames(file_list)
#print(suite)
runner = unittest.TextTestRunner(verbosity=3)
result = runner.run(suite)

С предыдущей структурой файловой системы ваша инструкция:

file_list.append("tests/test_%s.TestDocs" % some_file)

превращается в:

file_list.append("tests.test_%s.TestDocs" % some_file.split('.')[0])

Различия:

  1. из имени файла e1.py я убрал расширение с помощью инструкции split()
  2. я использовал точечную форму "tests.test_%s.TestDocs" % some_file вместо вашей "tests/test_%s.TestDocs" % some_file (см. здесь для документации по методу loadTestsFromName() и loadTestsFromNames()).

Результаты выполнения тестового набора

Содержимое test_e1.py:

import unittest
from production import e1

class TestDocs(unittest.TestCase):

    def test_01(self):
        e1.func1_of_e1()

    def test_02(self):
        e1.func2_of_e1()

Содержимое production/e1.py:

def func1_of_e1():
    print("func1_of_e1()")
    
def func2_of_e1():
    print("func2_of_e1()")

Итак, вывод выполнения:

test_01 (tests.test_e1.TestDocs) ... ok
test_02 (tests.test_e1.TestDocs) ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK
func1_of_e1()
func2_of_e1()

Таким образом, были выполнены 2 теста (test_01 и test_02), содержащиеся в test_e1.py, в то время как тесты, содержащиеся в файле test_e2.py (не показаны выше), не были выполнены, поскольку e2.py отсутствует в папке production.

Ответ или решение

Как запустить тесты только из определённых файлов в Python с использованием unittest

Когда вы работаете с модульными тестами в Python с помощью модуля unittest, может возникнуть необходимость выбирать, какие тесты запускать на основе наличия определённых файлов. В этом руководстве я опишу, как вы можете создать тестовый набор, который учитывает наличие файлов, и запускать только соответствующие тесты.

Предпосылки

  1. Структура каталогов: Для этого примера у нас есть следующая структура каталогов:
test_project
  ├── tests
  │   ├── __init__.py
  │   ├── test_e1.py
  │   ├── test_e2.py
  ├── production
  │   ├── e1.py
  ├── run_tests.py
  1. Содержимое тестов: В test_e1.py мы имеем следующие тесты:
import unittest
from production import e1

class TestDocs(unittest.TestCase):
    def test_01(self):
        e1.func1_of_e1()

    def test_02(self):
        e1.func2_of_e1()
  1. Основные файлы: Файл e1.py в каталоге production содержит две функции, которые мы будем тестировать.

Решение проблемы

Чтобы запустить только те тесты, которые зависят от наличия соответствующих файлов в каталоге, мы можем использовать метод loadTestsFromNames из unittest.TestLoader.

Шаги для реализации

  1. Импортируйте необходимые модули:
    Вам нужно будет импортировать модули os и unittest для работы с файловой системой и тестами.
import unittest
import os
  1. Определите файлы и их ожидаемые тесты:
    Создайте список файлов, которые нужно проверить, и соответствующих им тестов.
some_dir = "/path/to/production"
some_file_list = ["e1.py", "e2.py"]
  1. Создайте список тестов на основе наличия файлов:
    Используйте цикл для проверки наличия файлов и генерации списка тестов.
file_list = []

for some_file in some_file_list:
    full_filepath = os.path.join(some_dir, some_file)
    if not os.path.exists(full_filepath):
        continue
    file_list.append("tests.test_%s.TestDocs" % some_file.split('.')[0])
  1. Загрузите и запустите тесты:
    Используйте loadTestsFromNames для создания тестового набора и выполните его.
suite = unittest.TestLoader().loadTestsFromNames(file_list)
runner = unittest.TextTestRunner(verbosity=3)
result = runner.run(suite)

Пример кода run_tests.py

Вот полный код файла run_tests.py с учетом вышеизложенных моментов:

import unittest
import os

some_dir = "/path/to/production"
some_file_list = ["e1.py", "e2.py"]

file_list = []

for some_file in some_file_list:
    full_filepath = os.path.join(some_dir, some_file)
    if not os.path.exists(full_filepath):
        continue
    file_list.append("tests.test_%s.TestDocs" % some_file.split('.')[0])

suite = unittest.TestLoader().loadTestsFromNames(file_list)
runner = unittest.TextTestRunner(verbosity=3)
result = runner.run(suite)

Результаты выполнения

При запуске этого скрипта будут выполнены только те тесты, которые соответствуют присутствующим файлам в каталоге production. Например, если e1.py существует, тесты из test_e1.py будут выполнены, в то время как тесты из test_e2.py будут проигнорированы.

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

Заключение

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

Оцените материал
Добавить комментарий

Капча загружается...