38

私のDjangoプロジェクトにはユーティリティ関数があり、クエリセットを受け取り、そこからデータを取得して結果を返します。この関数のテストを書きたいと思います。QuerySetを「モック」する方法はありますか? データベースに触れないオブジェクトを作成したいのですが、使用する値のリスト (つまり、いくつかの偽の行) をオブジェクトに提供できます。これにより、クエリセットのように動作し、誰かがit/filter/get/all などでフィールド検索を行います。

このようなものはすでに存在しますか?

4

9 に答える 9

15

もちろん、QuerySet をモックできます。何でもモックできます。

自分でオブジェクトを作成し、必要なインターフェイスを与えて、好きなデータを返すようにすることができます。本質的に、モッキングは、テストの目的に十分に本物のように振る舞う「テストダブル」を提供することに他なりません。

始めるためのローテクな方法は、オブジェクトを定義することです:

class MockQuerySet(object):
    pass

次に、これらのいずれかを作成し、テストに渡します。テストは失敗しAttributeErrorます。これにより、 に何を実装する必要があるかがわかりますMockQuerySet。オブジェクトがテストに十分な量になるまで繰り返します。

于 2011-09-09T14:38:03.527 に答える
14

空のクエリセットの場合、keithhackbarth が既に述べているようnoneに、単純に使用します。

ただし、値のリストを返すクエリセットをモックするには、モデルのマネージャーでモックを使用することを好みますspec例として (Python 2.7 スタイル -外部の Mock ライブラリを使用しました)、クエリセットがフィルター処理されてからカウントされる簡単なテストを次に示します。

from django.test import TestCase
from mock import Mock

from .models import Example


def queryset_func(queryset, filter_value):
    """
    An example function to be tested
    """
    return queryset.filter(stuff=filter_value).count()


class TestQuerysetFunc(TestCase):

    def test_happy(self):
        """
        `queryset_func` filters provided queryset and counts result
        """
        m_queryset = Mock(spec=Example.objects)
        m_queryset.filter.return_value = m_queryset
        m_queryset.count.return_value = 97

        result = func_to_test(m_queryset, '__TEST_VALUE__')

        self.assertEqual(result, 97)
        m_queryset.filter.assert_called_once_with(stuff='__TEST_VALUE__')
        m_queryset.count.assert_called_once_with()

ただし、質問を満たすために、return_valueforを設定する代わりに、から返されるモデル インスタンスのcountになるように簡単に調整できます。listall

連鎖はfilter、モック化されたクエリセットを返すように設定することで処理されることに注意してください。

m_queryset.filter.return_value = m_queryset

excludeこれは、テスト対象の関数で使用されるすべてのクエリセット メソッド (例:など) に適用する必要があります。

于 2016-03-15T23:31:43.887 に答える
13

私は同じ問題を抱えています。いい人がQuerySetsをモックするためのライブラリを書いたようです。それはmock-djangoと呼ばれ、必要な特定のコードはここにあります https://github.com/dcramer/mock-django /blob/master/mock_django/query.pyその後、モデル オブジェクト関数にパッチを適用して、期待されるものを返すように設定したこれらの QuerySetMock オブジェクトの 1 つを返すことができると思います。

于 2012-09-10T12:33:40.017 に答える
5

これには、Django の .none() 関数を使用します。

例えば:

class Location(models.Model):
  name = models.CharField(max_length=100)
mock_locations = Location.objects.none()

これは、Django 自身の内部テスト ケースで頻繁に使用される方法です。コード内のコメントに基づく

Calling none() will create a queryset that never returns any objects and no
+query will be executed when accessing the results. A qs.none() queryset
+is an instance of ``EmptyQuerySet``.
于 2015-01-14T20:05:12.430 に答える
2

FactoryBoyを調べましたか?https://factoryboy.readthedocs.io/en/latest/orms.html これは、django orm をサポートするフィクスチャ置換ツールです。ファクトリは、基本的に orm のようなオブジェクトを (メモリ内またはテスト データベース内に) 生成します。

始めるための素晴らしい記事は次のとおりです: https://www.caktusgroup.com/blog/2013/07/17/factory-boy-alternative-django-testing-fixtures/

于 2019-04-04T02:41:42.573 に答える
-1

最初のアドバイスの 1 つは、関数を 2 つの部分に分割することです。1 つはクエリセットを作成し、もう 1 つはその出力を操作します。このようにして、2 番目の部分のテストは簡単です。

データベースの問題については、django が sqlite-in-memory を使用しているかどうかを調べたところ、最近のバージョンの django が sqlite-in-memory データベースを使用していることがわかりました(The django unittest pageから) 。

SQLite データベース エンジンを使用する場合、テストはデフォルトでインメモリ データベースを使用します (つまり、データベースはファイルシステムを完全にバイパスしてメモリ内に作成されます!)。

QuerySet オブジェクトをモックしても、その完全なロジックを実行することはできません。

于 2011-09-09T17:36:11.087 に答える
-20

私が知っていることではありませんが、実際のクエリセットを使用しないのはなぜですか? テストフレームワークはすべて、テスト内でサンプルデータを作成できるように設定されており、データベースはテストごとに再作成されるため、本物を使用しない理由はないようです.

于 2011-09-09T14:16:07.233 に答える