10

Запуск unittest с типичной структурой каталогов тестирования

15

У меня есть проблема с запуском юнит-тестов в структуре каталогов моего Python-проекта. Я использую довольно распространенную структуру, где тесты находятся в отдельной директории test. Вот пример структуры:

new_project/
    antigravity/
        antigravity.py
    test/
        test_antigravity.py
    setup.py
    и др.

Мой вопрос заключается в следующем: Каков обычный способ запуска тестов? Мне кажется, что это должно быть очевидно для всех, кроме меня, потому что нельзя просто выполнить команду python test_antigravity.py из каталога тестов, так как команда import antigravity не сработает, поскольку модуль не находится в пути.

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

Другой вариант — просто скопировать файл теста в другой каталог, но это кажется не самым разумным подходом и противоречит основной идее разделения тестов.

Так что, если бы вы только что скачали исходный код моего нового проекта, как бы вы запустили юнит-тесты? Я хотел бы получить ответ, который позволил бы мне сказать своим пользователям: "Чтобы запустить юнит-тесты, выполните X."

5 ответ(ов)

0

У меня была такая же проблема долгое время. В последнее время я выбрал следующую структуру директорий:

project_path
├── Makefile
├── src
│   ├── script_1.py
│   ├── script_2.py
│   └── script_3.py
└── tests
    ├── __init__.py
    ├── test_script_1.py
    ├── test_script_2.py
    └── test_script_3.py

В файле __init__.py в папке с тестами я добавил следующий код:

import os
import sys
PROJECT_PATH = os.getcwd()
SOURCE_PATH = os.path.join(
    PROJECT_PATH, "src"
)
sys.path.append(SOURCE_PATH)

Какую роль играет Makefile? Он очень важен для совместного использования проекта, поскольку гарантирует правильный запуск скриптов. В Makefile есть команда:

run_tests:
    python -m unittest discover .

Makefile важен не только из-за команды, которую он выполняет, но и из-за того, откуда он это делает. Если зайти в папку tests и выполнить python -m unittest discover ., это не сработает, потому что скрипт init в unit_tests вызывает os.getcwd(), который указывает на неправильный абсолютный путь (и этот путь будет добавлен в sys.path, в результате чего у вас не будет доступа к папке src). Тесты будут найдены, но не будут выполнены корректно. Поэтому Makefile нужен, чтобы избежать необходимости помнить об этой проблеме.

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

0

У меня была такая же проблема с отдельной папкой для модульных тестов. Из предложенных решений я добавил абсолютный путь к исходным файлам в sys.path.

Преимущество следующего решения в том, что вы можете запускать файл test/test_yourmodule.py, не переходя сначала в директорию с тестами:

import sys
import os

testdir = os.path.dirname(__file__)
srcdir = '../antigravity'
sys.path.insert(0, os.path.abspath(os.path.join(testdir, srcdir)))

import antigravity
import unittest

Таким образом, вы обеспечите доступ к модулю antigravity из вашей папки с тестами, что значительно упростит процесс тестирования.

0

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

Вы можете запустить следующую команду из директории "src":

python -m unittest discover -s ../test

Если вы хотите автоматизировать этот процесс и поместить команду в пакетный файл в вашей проектной директории, вы можете сделать это следующим образом:

setlocal & cd src & python -m unittest discover -s ../test

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

0

Вот перевод на русский в стиле ответа на StackOverflow.com:

Решение/Пример для модуля unittest в Python

Учитывая следующую структуру проекта:

ProjectName
 ├── project_name
 |    ├── models
 |    |    └── thing_1.py
 |    └── __main__.py
 └── test
      ├── models
      |    └── test_thing_1.py
      └── __main__.py

Вы можете запустить ваш проект из корневого каталога с помощью команды python project_name, что вызовет ProjectName/project_name/__main__.py.


Чтобы запустить ваши тесты с помощью команды python test, фактически выполняя ProjectName/test/__main__.py, вам необходимо сделать следующее:

1) Превратите ваш каталог test/models в пакет, добавив файл __init__.py. Это сделает доступными тестовые случаи из подкаталога из родительского каталога test.

# ProjectName/test/models/__init__.py

from .test_thing_1 import Thing1TestCase        

2) Измените вашу системную переменную sys.path в test/__main__.py, чтобы включить каталог project_name.

# ProjectName/test/__main__.py

import sys
import unittest

sys.path.append('../project_name')

loader = unittest.TestLoader()
testSuite = loader.discover('test')
testRunner = unittest.TextTestRunner(verbosity=2)
testRunner.run(testSuite)

Теперь вы можете успешно импортировать классы из project_name в ваших тестах.

# ProjectName/test/models/test_thing_1.py    

import unittest
from project_name.models import Thing1  # это не сработает без 'sys.path.append' в шаге 2

class Thing1TestCase(unittest.TestCase):

    def test_thing_1_init(self):
        thing_id = 'ABC'
        thing1 = Thing1(thing_id)
        self.assertEqual(thing_id, thing1.id)

Теперь вы готовы запускать ваши тесты без проблем! Если у вас есть дополнительные вопросы, не стесняйтесь спрашивать.

0

Python 3+

Дополняя @Pierre

Используя структуру каталогов для unittest, как показано ниже:

new_project
├── antigravity
│   ├── __init__.py         # создаем пакет
│   └── antigravity.py
└── test
    ├── __init__.py         # также создаем пакет для тестов
    └── test_antigravity.py

Чтобы запустить модуль тестов test_antigravity.py, выполните:

$ cd new_project
$ python -m unittest test.test_antigravity

Или можно запустить отдельный TestCase:

$ python -m unittest test.test_antigravity.GravityTestCase

Обязательно не забывайте добавлять __init__.py, даже если он пустой, иначе структура не будет работать.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь