Как запустить тестирование модулей Django с базой данных по умолчанию и неуправляемой базой данных? - PullRequest
0 голосов
/ 21 декабря 2018

У меня есть проект Django с базой данных по умолчанию, используемой для хранения таких вещей, как пользователь, заказы и т. Д.

У нас также есть неуправляемая база данных.Теперь, когда вы запускаете тест Django, они пытаются создать тестовые базы данных, но, поскольку у нас есть неуправляемая база данных, мы не можем этого сделать.Я не могу создать миграции этой базы данных, так как это приведет к 300 ошибкам при конфликте обратного метода доступа.

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

Я пробовал такие вещи, как создание миграций, но поскольку проблема с обратным доступом невозможна.

Есть ли способ использовать неуправляемыйбаза данных для модульного тестирования?База данных test_default, которую создает Django, в порядке, но я не могу создать базу данных test_unmanaged.

1 Ответ

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

Мы используем установку с управляемыми и неуправляемыми таблицами в одной и той же базе данных, которая также может работать для вашего варианта использования:

У нас есть скрипт для создания тестовой базы данных из двух дампов: test_structure.sql an test_fixtures.sql.Первый содержит структуру базы данных в определенный момент времени, включая все неуправляемые таблицы.Последний содержит любые данные, которые могут вам понадобиться в неуправляемых таблицах во время тестирования, и содержимое таблицы django_migrations.Мы сбрасываем test_fixtures.sql, используя сгенерированный список COPY (SELECT * FROM {table}) TO STDOUT;заявления, например: COPY (SELECT * FROM obs_00.django_migrations) TO STDOUT WITH NULL '--null--';.

Выходные данные psql -c {copy_statement} преобразуются в INSERT операторы с использованием такой функции:

def csv2sqlinsert(table_name, data):
    """
    Convert TSV output of  COPY (SELECT * FROM {table}) TO STDOUT
    to                     INSERT INTO {table} VALUES (), ()...();
    """

    def is_int(val):
        try:
            return "{}".format(int(val)) == val
        except ValueError:
            return False

    def column(data):
        if data == "--null--":
            return "null"
        elif is_int(data):
            return data
        else:
            return "'{}'".format(data.replace("'", "''"))  # escape quotes

    rows = [row.split("\t") for row in data.decode().split("\n") if len(row) > 1]

    if len(rows) == 0:
        return f"-- no data for {table_name}\n"

    data = ",\n".join("({})".format(",".join(column(col) for col in row)) for row in rows)

    ret = ""
    ret += f"-- {table_name} ({len(rows)} rows)\n"
    ret += f"INSERT INTO {table_name} VALUES\n{data};\n"

    return ret

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

создание тестовой базы данных

Определение имени тестовой базы данных в settings_test.py:

DATABASES["default"].update({
    "NAME": "django_test_db",
    "TEST": {"NAME": "django_test_db",},
})

С двумя вышеуказанными файлами, (re)Создание тестовой базы данных выглядит следующим образом:

dropdb django_test_db
createdb django_test_db
psql -d django_test_db -f test_structure.sql
psql -d django_test_db < test_fixtures.sql

Теперь у нас есть состояние базы данных на момент создания дампа.Поскольку могут быть новые миграции, мы позволяем django мигрировать:

./manage.py migrate --settings=settings_test

Запуск тестов

Теперь мы можем запускать тесты, используя ./manage.py test --settings=settings_test.Поскольку воссоздание базы данных при каждом запуске теста может занять значительное время, добавление --keepdb сэкономит вам много времени в ожидании процедуры восстановления тестовой базы данных.

Мы изменили manage.py вот такмы не можем забыть:

#!/usr/bin/env python
import os
import sys

if __name__ == "__main__":
    if len(sys.argv) > 1 and sys.argv[1] == "test":
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings_test")
        cmd = sys.argv + ["--keepdb"]
    else:
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")
        cmd = sys.argv

    from django.core.management import execute_from_command_line
    execute_from_command_line(cmd)
...