28

FileFieldを持ついくつかのモデルのテストを作成しようとしています。モデルは次のようになります。

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

私は2つの問題に遭遇しました:

  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にこれを処理する別の方法があるかどうか疑問に思いました。

私が考えていた解決策の1つは、テストフィクスチャとの同期を維持する必要があるテストに別のメディアフォルダーを使用することでした。settings.pyテストの実行中に別のメディアディレクトリを指定する方法はありますか?また、メディアフォルダ内のファイルを同期するために、dumpdataへのある種のフックを含めることはできますか?

それで、ファイルを含む単体テストを処理するためのよりPythonicまたはDjango固有の方法はありますか?

4

5 に答える 5

30

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の魔法の機能の1つであり、ドキュメントに表示されません:)。ただし、ここで参照されます。

于 2013-12-11T01:10:01.557 に答える
5

文書化されているように、デコレータを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
于 2014-01-10T05:44:49.747 に答える
3

以前にギャラリーアプリ全体の単体テストを作成しましたが、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()メソッドでこれらのメソッドを実行すると、うまく機能します。再利用可能で予測可能なファイルフィールドをテストするためのファイルのクリーンコピーがあります。

于 2010-02-15T22:14:23.020 に答える
1

pytestとpytest-djangoを使用して、これをconftest.pyファイルで使用します。

import tempfile
import shutil
from pytest_django.lazy_django import skip_if_no_django
from pytest_django.fixtures import SettingsWrapper


@pytest.fixture(scope='session')
#@pytest.yield_fixture()
def settings():
    """A Django settings object which restores changes after the testrun"""
    skip_if_no_django()

    wrapper = SettingsWrapper()
    yield wrapper
    wrapper.finalize()


@pytest.fixture(autouse=True, scope='session')
def media_root(settings):
    tmp_dir = tempfile.mkdtemp()
    settings.MEDIA_ROOT = tmp_dir
    yield settings.MEDIA_ROOT
    shutil.rmtree(tmp_dir)


@pytest.fixture(scope='session')
def django_db_setup(media_root, django_db_setup):
    print('inject_after')

役立つかもしれません:

  1. https://dev.funkwhale.audio/funkwhale/funkwhale/blob/de777764da0c0e9fe66d0bb76317679be964588b/api/tests/conftest.py
  2. https://framagit.org/ideascube/ideascube/blob/master/conftest.py
  3. https://stackoverflow.com/a/56177770/5305401
于 2020-09-10T06:12:00.257 に答える
0

これは私が私のテストのためにしたことです。ファイルをアップロードすると、組織モデルオブジェクトの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)
于 2012-05-04T20:12:29.367 に答える