2010-02-15 3 views
22

Я пытаюсь построить тесты для некоторых моделей, имеющих FileField. Модель выглядит следующим образом:Django test 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 способ использования модульных тестов с участием файлов?

+0

Так os.remove (Foo) does't работы? Вызывает ли это исключение? Возможно, в этом каталоге/файле нет правильных привилегий, чтобы иметь возможность удалять их изнутри вашего модульного теста? –

+0

'os.remove() 'в коде удаляет файл из каталога temp. Чтобы удалить загруженный файл, мне придется искать в медиа-каталоге и выполнять более сложную логику, чтобы найти точное местоположение файла. Я ищу более простой, автоматический способ сделать это, если он даже существует. – sttwister

+1

D'oh, извините! Я неправильно прочитал ваш пост. Как насчет хакерских настроек.MEDIA_ROOT = '/ path/to/project/static/и/then/alternative/storage /' и settings.MEDIA_URL = '/ static/and/then/alternative/storage /' в вашем setUp для ваших тестов ? Хакки, но мог бы выполнить эту работу ... –

ответ

17

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

from django.core.files.uploadedfile import SimpleUploadedFile 

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

Это одна из магических черт-это-не-шоу-вверх-в докторантов Джанго :). Однако это относится к here.

+3

Небиновое содержимое вызывает ошибку в Python 3+; вы можете исправить это, просто сделав содержимое двоичным, например: 'my_model.file_field = SimpleUploadedFile ('best_file_eva.txt', b'these - это содержимое файла! ')' – LaundroMat

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) 

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

+0

Я не вижу, как это может мне помочь. Я хочу перезаписать медиа-каталог Django тестовым. И я также хочу как-то экспортировать/скопировать файлы при использовании './manage.py dumpdata'. – sttwister

+0

Переписывание медиа-каталога django - плохая идея. Если вы не переместите текущий медиа-каталог где-то еще и не вернете его, вы никогда не сможете запускать тесты на своем живом сайте, потому что это будет деструктивная операция. Вы * можете * переместить папку мультимедиа и вернуть ее с помощью затворов, как я предложил выше. Кроме того, dumpdata никогда не будет экспортировать файлы для вас. Для этого вам придется написать свой собственный скрипт или расширение manage.py. –

0

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

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

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

from django.test import override_settings 


@override_settings(MEDIA_ROOT='/tmp/django_test') 
def test_post_solution_file(self): 
    # your code here 
Смежные вопросы