Определение тестовых методов в базовом классе, которые не должны быть инстанцированы напрямую

Я пытаюсь создать тестовые случаи, которые отличаются только тем, какой пользователь вошел в систему. Поэтому я решил, что определение тестов в базовом классе и создание подклассов, которые регистрируют пользователя во время setUp(), будет правильным решением.

Однако я не могу найти элегантное решение для исключения тестов в базовом классе из выполнения.

from django.contrib.auth.models import User
from django.test import TestCase


class A(TestCase):
    @classmethod
    def setUpTestData(cls):
        cls.user_a = User.objects.create_user("a", "", "a")
        cls.user_b = User.objects.create_user("b", "", "b")

    def setUp(self):
        # global set up stuff here
        ...

    def test_1(self):
        self.assertEqual(self.user_a.username, "a")


class SubA(A):
    def setUp(self):
        super().setUp()
        self.client.force_login(self.user_a)


class SubB(A):
    def setUp(self):
        super().setUp()
        self.client.force_login(self.user_b)

В приведенном выше коде я хочу, чтобы выполнялись только унаследованные тесты в классах SubA и SubB, но не тесты в A.

Я пробовал:

  • Извлечение базового класса в другой модуль, который не включен в шаблон поиска по умолчанию. => все равно выполняются тесты, поскольку базовый класс должен быть импортирован, чтобы наследоваться от него
  • .
  • определение load_tests(...) функции в пакете, исключающем базовый класс => тот же результат, что и выше
  • повышение unittest.SkipTest в базовом классе setUp() и перехват его в подклассах setUp => работает, но добавляет все тесты в базовом классе как "пропущенные"

Итак, мой вопрос заключается в следующем: Есть ли способ исключить тесты в базовом классе (который должен наследоваться от TestCase Django) из выполнения без записи их как пропущенных и, желательно, без необходимости дополнительных параметров в моей команде ./manage.py test?

Может быть, использовать средства subTest тестового фреймворка?

class A(TestCase):
    ... # setups as before

    def test1( self):
        for user in ( self.user_a, self.user_b):
            with self.subTest( user=user):
                self.client.force_login( user)

                # and now the test(s) that you want to execute both for user_a and user_b
                self.assertEqual(user.username, "a")

Если подтест проваливается, содержащий его тест не останавливается, а начинается следующий подтест в итерации. kwarg к self.subTest выводится как часть сообщения о неудаче подтеста. Если (как в данном случае) переданная сущность не является строкой, она преобразуется в str. Если это приведет к неудаче или выдаст глупый вывод, вы можете выполнить собственное преобразование, например self.subTest( user=f"{user.username} (pk={user.pk})" )

(если вы видели это пять минут назад, я удалил свое другое предложение, потому что, поразмыслив, я не увидел, что оно может быть полезным. Если я ошибаюсь, предложение состояло в том, что вы могли бы поместить тестовые процедуры в класс mixin, производный от object, и наследовать их в классах TestCase A и B)

Вернуться на верх