Django test FileField с использованием тестовых приспособлений - PullRequest
24 голосов
/ 15 февраля 2010

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

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

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

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

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

    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, чтобы он синхронизировал файлы в медиа-папках?

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

Ответы [ 4 ]

21 голосов
/ 11 декабря 2013

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

from django.core.files.uploadedfile import SimpleUploadedFile

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

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

5 голосов
/ 10 января 2014

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

from django.test import override_settings


@override_settings(MEDIA_ROOT='/tmp/django_test')
def test_post_solution_file(self):
  # your code here
3 голосов
/ 16 февраля 2010

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

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

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 () моих модульных тестов, и это прекрасно работает! У вас есть чистая копия ваших файлов для проверки вашего файлового поля, пригодного для повторного использования и предсказуемого.

0 голосов
/ 05 мая 2012

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

    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)
...