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

Тест Django FileField с использованием тестовых приборов

Я пытаюсь построить тесты для некоторых моделей, имеющих FileField. Модель выглядит следующим образом:

class SolutionFile(models.Model):
    '''
    A file from a solution.
    '''
    solution = models.ForeignKey(Solution)
    file = models.FileField(upload_to=make_solution_file_path)

Я столкнулся с двумя проблемами:

  • При сохранении данных на прибор с помощью ./manage.py dumpdata содержимое файла не сохраняется, только имя файла сохраняется в приборе. Хотя я считаю, что это ожидаемое поведение, поскольку содержимое файла не сохраняется в базе данных, я хотел бы как-то включить эту информацию в прибор для тестирования.

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

    def test_post_solution_file(self):
        import tempfile
        import os
        filename = tempfile.mkstemp()[1]
        f = open(filename, 'w')
        f.write('These are the file contents')
        f.close()
        f = open(filename, 'r')
        post_data = {'file': f}
        response = self.client.post(self.solution.get_absolute_url()+'add_solution_file/', post_data,
                                    follow=True)
        f.close()
        os.remove(filename)
        self.assertTemplateUsed(response, 'tests/solution_detail.html')
        self.assertContains(response, os.path.basename(filename))
    

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

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

Итак, существует ли более питоновский или Django-специфический способ решения модульных тестов с участием файлов?

4b9b3361

Ответ 1

Django предоставляет отличный способ писать тесты на FileFields без разбора в реальной файловой системе - используйте SimpleUploadedFile.

from django.core.files.uploadedfile import SimpleUploadedFile

my_model.file_field = SimpleUploadedFile('best_file_eva.txt', b'these are the contents of the txt file')

Это одна из магических функций Django, которые не появляются в документах :). Однако он упоминается здесь как here.

Ответ 2

Вы можете переопределить параметр MEDIA_ROOT для своих тестов с помощью @override_settings() decorator как описано в документе:

from django.test import override_settings


@override_settings(MEDIA_ROOT='/tmp/django_test')
def test_post_solution_file(self):
  # your code here

Ответ 3

Я уже писал единичные тесты для всего приложения галереи, и то, что сработало для меня, было использование модулей tempfile и shutil для python для создания копий тестовых файлов во временных каталогах, а затем впоследствии удалить их.

Следующий пример не работает/завершен, но должен привести вас к правильному пути:

import os, shutil, tempfile

PATH_TEMP = tempfile.mkdtemp(dir=os.path.join(MY_PATH, 'temp'))

def make_objects():
    filenames = os.listdir(TEST_FILES_DIR)

    if not os.access(PATH_TEMP, os.F_OK):
        os.makedirs(PATH_TEMP)

    for filename in filenames:
        name, extension = os.path.splitext(filename)
        new = os.path.join(PATH_TEMP, filename)
        shutil.copyfile(os.path.join(TEST_FILES_DIR, filename), new)

        #Do something with the files/FileField here

def remove_objects():
    shutil.rmtree(PATH_TEMP)

Я запускаю эти методы в методах setUp() и tearDown() моих модульных тестов, и он отлично работает! У вас есть чистая копия ваших файлов, чтобы проверить ваше файловое поле, которое можно использовать повторно и предсказуемо.

Ответ 4

Это то, что я сделал для своего теста. После того, как вы загрузили файл, он должен закончиться в качестве свойства фотографии моего объекта модели организации:

    import tempfile
    filename = tempfile.mkstemp()[1]
    f = open(filename, 'w')
    f.write('These are the file contents')
    f.close()
    f = open(filename, 'r')
    post_data = {'file': f}
    response = self.client.post("/org/%d/photo" % new_org_data["id"], post_data)
    f.close()
    self.assertEqual(response.status_code, 200)

    ## Check the file
    ## org is where the file should end up
    org = models.Organization.objects.get(pk=new_org_data["id"])
    self.assertEqual("These are the file contents", org.photo.file.read())

    ## Remove the file
    import os
    os.remove(org.photo.path)