69

settings次の形式の属性を必要とする Django アプリがあります。

RELATED_MODELS = ('appname1.modelname1.attribute1',
                  'appname1.modelname2.attribute2', 
                  'appname2.modelname3.attribute3', ...)

attributeN次に、post_save シグナルをフックして、定義に応じて他の固定モデルを更新します。

この動作をテストしたいと思います。このアプリがプロジェクト内の唯一のアプリであっても、テストは機能するはずです (独自の依存関係を除いて、他のラッパー アプリをインストールする必要はありません)。テスト データベース専用のモック モデルを作成してアタッチ/登録/アクティブ化するにはどうすればよいですか? (または、まったく可能ですか?)

テストフィクスチャを使用できるようにするソリューションは素晴らしいでしょう。

4

11 に答える 11

54

テストを(ファイルtests/ではなく) アプリのサブディレクトリに配置し、テスト専用モデルに を含めることができます。tests.pytests/models.py

次に、 「アプリ」を含むテスト実行スクリプト () を提供します。(実際のプロジェクトからアプリ テストを実行する場合、これは機能しません。このプロジェクトにはテスト アプリがありませんが、プロジェクトから再利用可能なアプリ テストを実行することが役立つことはめったになく、Django 1.6+ は既定では機能しません。 )tests/INSTALLED_APPSINSTALLED_APPS

(: 以下で説明する代替の動的メソッドは、テスト ケースがサブクラス化されている場合にのみ Django 1.1+ で機能し、TransactionTestCaseこれによりテストが大幅に遅くなり、Django 1.7+ ではまったく機能しなくなります。これは、歴史的な関心のためにここに残されています。これを使って。)

テストの開始時 (つまり、setUp メソッド内、または一連の doctests の開始時) に、動的に"myapp.tests"INSTALLED_APPS 設定を追加してから、次のようにすることができます。

from django.core.management import call_command
from django.db.models import loading
loading.cache.loaded = False
call_command('syncdb', verbosity=0)

次に、テストの最後に、古いバージョンの INSTALLED_APPS を復元し、アプリのキャッシュを再度クリアしてクリーンアップする必要があります。

このクラスはパターンをカプセル化するため、テスト コードがそれほど煩雑になることはありません。

于 2009-02-02T14:49:31.953 に答える
19

@paluhの答えでは、テスト以外のファイルに不要なコードを追加する必要があります。私の経験では、@ carlのソリューションは、django.test.TestCaseフィクスチャを使用するために必要なものでは機能しません。を使用する場合は、フィクスチャがロードされる前にdjango.test.TestCase必ず呼び出す必要があります。syncdbこれには、メソッドをオーバーライドする必要があります_pre_setup(メソッドにコードを入れるsetUpだけでは不十分です)。TestCaseテストモデルを使用してアプリを追加できる独自のバージョンを使用しています。これは次のように定義されます。

from django.conf import settings
from django.core.management import call_command
from django.db.models import loading
from django import test

class TestCase(test.TestCase):
    apps = ()

    def _pre_setup(self):
        # Add the models to the db.
        self._original_installed_apps = list(settings.INSTALLED_APPS)
        for app in self.apps:
            settings.INSTALLED_APPS.append(app)
        loading.cache.loaded = False
        call_command('syncdb', interactive=False, verbosity=0)
        # Call the original method that does the fixtures etc.
        super(TestCase, self)._pre_setup()

    def _post_teardown(self):
        # Call the original method.
        super(TestCase, self)._post_teardown()
        # Restore the settings.
        settings.INSTALLED_APPS = self._original_installed_apps
        loading.cache.loaded = False
于 2010-04-20T04:00:49.257 に答える
16

プロジェクトで使用するソリューションを共有しました。多分それは誰かを助けるでしょう。

pip install django-fake-model

偽のモデルを作成するための 2 つの簡単な手順:

1)任意のファイルでモデルを定義します(通常、テストケースの近くのテストファイルでモデルを定義します)

from django_fake_model import models as f


class MyFakeModel(f.FakeModel):

    name = models.CharField(max_length=100)

2) TestCaseまたはテスト関数にデコレータ@MyFakeModel.fake_meを追加します。

class MyTest(TestCase):

    @MyFakeModel.fake_me
    def test_create_model(self):
        MyFakeModel.objects.create(name='123')
        model = MyFakeModel.objects.get(name='123')
        self.assertEqual(model.name, '123')

このデコレーターは、各テストの前にデータベースにテーブルを作成し、テスト後にテーブルを削除します。

また、テーブルを手動で作成/削除するMyFakeModel.create_table()こともできます: /MyFakeModel.delete_table()

于 2015-09-28T14:17:53.437 に答える
11

このソリューションは、以前のバージョンのdjango(before 1.7) でのみ機能します。バージョンを簡単に確認できます。

import django
django.VERSION < (1, 7)

元の応答:

それは非常に奇妙ですが、フォームミーは非常に単純なパターンで機能します:

  1. テストするアプリに tests.py を追加し、
  2. このファイルでは、テスト モデルを定義するだけで、
  3. 以下にテストコード (doctest または TestCase 定義) を置きます。

以下に、テストにのみ必要な記事モデルを定義するコードをいくつか入れました (これは someapp/tests.py に存在し、次のコマンドでテストできます: ./manage.py test someapp ):

class Article(models.Model):
    title = models.CharField(max_length=128)
    description = models.TextField()
    document = DocumentTextField(template=lambda i: i.description)

    def __unicode__(self):
        return self.title

__test__ = {"doctest": """
#smuggling model for tests
>>> from .tests import Article

#testing data
>>> by_two = Article.objects.create(title="divisible by two", description="two four six eight")
>>> by_three = Article.objects.create(title="divisible by three", description="three six nine")
>>> by_four = Article.objects.create(title="divisible by four", description="four four eight")

>>> Article.objects.all().search(document='four')
[<Article: divisible by two>, <Article: divisible by four>]
>>> Article.objects.all().search(document='three')
[<Article: divisible by three>]
"""}

単体テストは、そのようなモデル定義でも機能します。

于 2009-12-01T16:24:59.860 に答える
10

関連する回答からの引用:

モデルをテスト用に定義したい場合は、 Django チケット #7835、特にコメント #24の一部を以下に示します:

明らかに、tests.py でモデルを直接定義するだけです。Syncdb は tests.py をインポートしないため、これらのモデルは通常のデータベースに同期されませんが、テスト データベースに同期され、テストで使用できます。

于 2013-03-17T12:34:18.393 に答える
10

テストのためだけにモデルを動的に作成するために、より結合されたものではありますが、少し異なるアプローチを選択しました。

すべてのテストをアプリ内のtestsサブディレクトリに保存しfilesます。サブディレクトリ内のmodels.pyファイルにtestsは、テスト専用モデルが含まれています。結合された部分がここに来ます。ここで、settings.pyファイルに次を追加する必要があります。

# check if we are testing right now
TESTING = 'test' in sys.argv

if TESTING:
    # add test packages that have models
    INSTALLED_APPS += ['files.tests',]

また、テスト モデルに db_table を設定しました。そうしないと、Django が という名前のテーブルを作成しtests_<model_name>、別のアプリの他のテスト モデルと競合する可能性があるためです。これが私のテストモデルです:

class Recipe(models.Model):

    '''Test-only model to test out thumbnail registration.'''

    dish_image = models.ImageField(upload_to='recipes/')

    class Meta:
        db_table = 'files_tests_recipe'
于 2012-01-03T22:10:32.480 に答える
4

あなたの答え、特に@slacyの答えを組み合わせて、私はこれをしました:

class TestCase(test.TestCase):
    initiated = False

    @classmethod
    def setUpClass(cls, *args, **kwargs):
        if not TestCase.initiated:
            TestCase.create_models_from_app('myapp.tests')
            TestCase.initiated = True

        super(TestCase, cls).setUpClass(*args, **kwargs)

    @classmethod
    def create_models_from_app(cls, app_name):
        """
        Manually create Models (used only for testing) from the specified string app name.
        Models are loaded from the module "<app_name>.models"
        """
        from django.db import connection, DatabaseError
        from django.db.models.loading import load_app

        app = load_app(app_name)
        from django.core.management import sql
        from django.core.management.color import no_style
        sql = sql.sql_create(app, no_style(), connection)
        cursor = connection.cursor()
        for statement in sql:
            try:
                cursor.execute(statement)
            except DatabaseError, excn:
                logger.debug(excn.message)

これにより、db テーブルを複数回作成しようとする必要がなくなり、INSTALLED_APPS を変更する必要がなくなります。

于 2012-05-18T18:13:06.933 に答える
4

これを行うために私が使用しているパターンは次のとおりです。

サブクラス化されたバージョンの TestCase で使用するこのメソッドを作成しました。次のようになります。

@classmethod
def create_models_from_app(cls, app_name):
    """
    Manually create Models (used only for testing) from the specified string app name.
    Models are loaded from the module "<app_name>.models"
    """
    from django.db import connection, DatabaseError
    from django.db.models.loading import load_app

    app = load_app(app_name)
    from django.core.management import sql
    from django.core.management.color import no_style
    sql = sql.sql_create(app, no_style(), connection)
    cursor = connection.cursor()
    for statement in sql:
        try:
            cursor.execute(statement)
        except DatabaseError, excn:
            logger.debug(excn.message)
            pass

myapp/tests/models.py次に、 INSTALLED_APPS に含まれていないような特別なテスト固有の models.py ファイルを作成します。

私の setUp メソッドで create_models_from_app('myapp.tests') を呼び出すと、適切なテーブルが作成されます。

このアプローチの唯一の「落とし穴」は、実行するたびにモデルを作成したくないということですsetUp。これが、DatabaseError をキャッチする理由です。このメソッドの呼び出しをテスト ファイルの先頭に置くと、少しはうまくいくと思います。

于 2012-04-18T21:55:11.757 に答える