Pytest-django: не может удалить БД после тестов - PullRequest
0 голосов
/ 25 декабря 2018

У меня есть приложение Django, и я пытаюсь протестировать его, используя pytest и pytest-django.Однако довольно часто, когда тесты заканчиваются, я получаю сообщение об ошибке, что база данных не может быть удалена: DETAIL: There is 1 other session using the database.

По сути, минимальный тестовый код, к которому я могу его сузить, равен:

@pytest.fixture
def make_bundle():
    a = MyUser.objects.create(key_id=uuid.uuid4())
    return a


class TestThings:
    def test_it(self, make_bundle):
        all_users = list(MyUser.objects.all())
        assert_that(all_users, has_length(1))

Время от времени тесты завершаются неудачей с вышеуказанной ошибкой.Есть ли что-то, что я делаю не так?Или как я могу это исправить?

База данных, которую я использую, - это PostgreSQL 9.6.

1 Ответ

0 голосов
/ 25 декабря 2018

Я публикую это как ответ, потому что мне нужно опубликовать кусок кода и потому что это сработало.Тем не менее, это выглядит как грязный хак для меня, и я буду более чем рад принять чей-либо ответ, если он будет лучше.Вот мое решение: в основном, добавьте необработанный sql, который выгоняет всех пользователей из данного db, в метод, который уничтожает db.И сделать это с помощью обезьяньего патча.Чтобы убедиться, что monkeypatching происходит перед тестами, добавьте его в корневой conftest.py файл как автоматическое исправление:

def _destroy_test_db(self, test_database_name, verbosity):
    """
    Internal implementation - remove the test db tables.
    """
    # Remove the test database to clean up after
    # ourselves. Connect to the previous database (not the test database)
    # to do so, because it's not allowed to delete a database while being
    # connected to it.
    with self.connection._nodb_connection.cursor() as cursor:
        cursor.execute(
            "SELECT pg_terminate_backend(pg_stat_activity.pid) "
            "FROM pg_stat_activity "
            "WHERE pg_stat_activity.datname = '{}' "
                "AND pid <> pg_backend_pid();".format(test_database_name)
        )

        cursor.execute("DROP DATABASE %s"
                       % self.connection.ops.quote_name(test_database_name))


@pytest.fixture(autouse=True)
def patch_db_cleanup():
    creation.BaseDatabaseCreation._destroy_test_db = _destroy_test_db

Обратите внимание, что код отключения может зависеть от вашего механизма базы данных и метода, которыйПотребность в мартышках может отличаться в разных версиях Django.

...