Подтвердить что ты не робот

Запуск определенных тестов Django (с django-носом?)

У меня очень сложный файл tests.py.

Собственно, классы тестов и методы генерируются во время выполнения w/ type (для учета данных, перечисленных во вспомогательных файлах). Я делаю вещи следующим образом (см. Ниже для получения более кода):

klass = type(name, (TestCase,), attrs)
setattr(current_module, name, klass)

FYI, с обычным тестовым бегуном django, все эти тесты запускаются при выполнении ./manage.py test myapp (благодаря показанному выше setattr).

Я хочу выполнить только часть этих тестов, не перечисляя их имена вручную.

Например, я могу дать каждому тегу "теги" в именах классов или именах методов, чтобы я мог их фильтровать. Например, я бы выполнил: запустите все тесты, имя метода содержит строку "test_postgres_backend _"

Я попытался использовать django-nose из-за опции nose -m, которая должна иметь возможность выбирать тесты на основе регулярных выражений - идеальное решение моей проблемы.

К сожалению, вот что происходит при использовании django-носа в качестве тест-лидера django:

  • ./manage.py test myapp не находит автоматически type -генерированные тестовые классы (в отличие от тестового бегуна django)
  • ни ./manage.py test -m ".*" myapp, ни ./manage.py test myapp -m ".*" найдите ЛЮБОЙ тест, , даже если обычные нормальные TestCase классы присутствуют в файле

Итак:

  • У вас есть другое решение моей общей проблемы, вместо того, чтобы пытаться использовать django-nose -m?
  • С django-nose, знаете ли вы, как сделать работу -m?

mcve

Добавьте в пустой файл myapp/tests.py следующее:

from django.test import TestCase
from sys import modules


current_module = modules[__name__]


def passer(self, *args, **kw):
    self.assertEqual(1, 1)


def failer(self, *args, **kw):
    self.assertEqual(1, 2)


# Create a hundred ...
for i in xrange(100):
    # ... of a stupid TestCase class that has 1 method that passes if `i` is
    # even and fails if `i` is odd
    klass_name = "Test_%s" % i
    if i % 2:  # Test passes if even
        klass_attrs = {
            'test_something_%s' % i: passer
        }
    else:      # Fail if odd
        klass_attrs = {
            'test_something_%s' % i: failer
        }
    klass = type(klass_name, (TestCase,), klass_attrs)

    # Set the class as "child" of the current module so that django test runner
    # finds it
    setattr(current_module, klass_name, klass)

Если делает для этого выходного запуска (в порядке alphab) django test runnner:
F.F.F.F.F.F.FF.F.F.F.F..F.F.F.F.F.FF.F.F.F.F..F.F.F.F.F.FF.F.F.F.F..F.F.F.F.F.FF.F.F.F.F..F.F.F.F.F..

Если вы перейдете на django_nose test runner, ничего не произойдет на ./manage.py test myapp.

После исправления этого, я бы хотел, чтобы он мог запускать только те методы тестирования, имена которых заканчиваются символом 0 (или какой-либо другой тип фильтрации с возможностью повторного поиска)

4b9b3361

Ответ 1

Проблема, с которой вы столкнулись, заключается в том, что Nose определяет, включать или нет метод в набор тестов для запуска, просматривая имя, записанное в самой функции, а не атрибут, предоставляющий доступ к этой функции. Если я переименую ваши passer и failer в test_pass и test_fail, то Nose сможет найти тесты. Поэтому сами функции должны быть названы таким образом, чтобы они соответствовали тому, что дано -m (или по умолчанию).

Здесь измененный код, который дает ожидаемые результаты:

from django.test import TestCase
from sys import modules

current_module = modules[__name__]

def test_pass(self, *args, **kw):
    self.assertEqual(1, 1)

def test_fail(self, *args, **kw):
    self.assertEqual(1, 2)

# Create a hundred ...
for i in xrange(100):
    # ... of a stupid TestCase class that has 1 method that passes if `i` is
    # even and fails if `i` is odd
    klass_name = "Test_%s" % i
    if i % 2:  # Test passes if even
        klass_attrs = {
            'test_something_%s' % i: test_pass
        }
    else:      # Fail if odd
        klass_attrs = {
            'test_something_%s' % i: test_fail
        }
    klass = type(klass_name, (TestCase,), klass_attrs)

    # Set the class as "child" of the current module so that django test runner
    # finds it
    setattr(current_module, klass_name, klass)

# This prevents Nose from seeing them as tests after the loop is over.
test_pass = None
test_fail = None

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

Другой способ получить те же результаты - определить __test__ для двух ваших функций:

def passer(self, *args, **kw):
    self.assertEqual(1, 1)
passer.__test__ = 1

def failer(self, *args, **kw):
    self.assertEqual(1, 2)
failer.__test__ = 1

И в конце файла:

# This prevents Nose from seeing them as tests after the loop is over.
passer = None
failer = None

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

Логику, определяющую выбор методов, можно найти в файле Nose selector.py в wantMethod:

def wantMethod(self, method):
        """Is the method a test method?
        """
        try:
            method_name = method.__name__
        except AttributeError:
            # not a method
            return False
        if method_name.startswith('_'):
            # never collect 'private' methods
            return False
        declared = getattr(method, '__test__', None)
        if declared is not None:
            wanted = declared
        else:
            wanted = self.matches(method_name)
        plug_wants = self.plugins.wantMethod(method)
        if plug_wants is not None:
            wanted = plug_wants
        log.debug("wantMethod %s? %s", method, wanted)
        return wanted

Я не вижу ясного способа использовать -m для запуска только некоторых тестов так, как вы этого хотите. Проблема в том, что -m одинаково совпадает с именами файлов, директив, модулей, классов и функций. Если вы установите что-то вроде -m0$, тогда все отдельные части, которые я только что привел, должны соответствовать регулярному выражению для выбранного теста. (Нос не объединяет их, а затем сопоставляется по комбинации.) Можно индивидуально перечислить тесты в командной строке, но это плохой заменитель регулярного выражения.

Ответ 2

В общем, вы можете запустить свой конкретный тест с чем-то вроде этого:

# assuming your tests are in core/tests.py
python manage.py test core.tests:CoreTestCase.my_specific_test

Вы пробовали этот подход?