6

作業中の API に Django REST Framework を使用しています。いくつかの理由から、クラスベースのビューを使用したいと考えています。ただし、私は単体テストに少しこだわりがあり、単体テストがデータベースに触れることは決して許しません。注: 私は常に、Carl Meyer が Pycon 2012 で示した「トリック」を使用します。そこで彼は Cursor ラッパーをモックアウトします。

cursor_wrapper = Mock()
cursor_wrapper.side_effect = RuntimeError("No touching the database!")

@patch('django.db.backends.util.CursorWrapper', cursor_wrapper)
class TestMyCode(TestCase):

スライドに興味がある場合は、ここにリンクがあります。

ビューの 1 つに、データベース内の何かをチェックするメソッドがあります。DRY であるためには、POST と PUT の間で共有されます。しかし、単体テストのためにそれをモックするのに問題があります。これは、クラスメソッド as_view が新しいインスタンスとクラスのディスパッチを作成し、ディスパッチが返す「ハンドラ」関数を返すためです。そのため、クラスベースのビューで共有メソッドを取得してモックすることができないようです。

クラス ベースのビューで使用されるモデルをモック アウトすることはできますが、「DRY」であるという目標を本質的に破り、POST と PUT の両方でコードをコピーする必要があります。コードをリファクタリングして、ロジックをモデルに移動できると思います。しかし、私はそれをやりたいとは思っていません。

クラスベースのビューの共有メソッドをモックアウトして、実際にデータベースに触れないようにするにはどうすればよいでしょうか? それらを避けるだけですか?

4

1 に答える 1

4

あなたはあなた自身の質問に答えたと思います。制御の反転や依存性注入など、Web フレームワークのテストに使用するものと同じことが Django にも適用されます。Python では非常にシンプルに保つことができるので、たとえば Spring などに存在するものに怯えたり、興味をそそられたりしないでください。

クラスベースのビューからコードを移動してみませんか? 何らかの理由で他の場所で同じロジックが必要な場合、コードはまだ DRY にはなりません。Django だからといって、優れたプログラミング原則が適用されないわけではありません。

サービス (Django のサービス定義ではなく概念として) などの新しいクラス/Python モジュールや、データ アクセスのためのその他の論理抽象化でいくつかのものを抽象化することをお勧めします。これにより、Django ビューのリクエスト/レスポンス ライフサイクルから完全に独立します。Django と Rails の開発者は、すべてのロジックをモデルまたはビューに直接配置する傾向があります。これは、神のクラスやテストが難しいものにつながるだけです。

ビューを、マーシャリング パラメータ (GET/POST) などをコードの残りの部分に処理し、別の場所にカプセル化された必要なロジックを呼び出す軽い抽象化と考えることで、これを容易にすることもできます。IMO、テスト可能なコードが必要な場合、プロセスにとって絶対に重要でない限り、ロジックの 99% は Web コンテキストの外にある必要があります。これにより、バックグラウンドでの並列実行も容易になります。

最終的に得られるのは、HTTP に直接依存していないため、テストが容易な通常の python モジュールとクラスです。HTTP をモックする必要がある場合は、単にリクエスト オブジェクトをモックできます。幸いなことに、python/django の組み合わせにより、これらのものを単純な dict/kwargs として簡単にダンプしてモックできます。

クラスベースのビューを使用して気づいたことの 1 つは、ミックスインで使用し、いくつかの規則 (json を返す、グラフのプロパティを開くなど) を適用するのに適していることですが、DetailView などのモデルを直接必要とするより「高度な」クラスベースのビューを使用するだけです。不必要に物事を複雑にします。これらのビューは、管理画面には適していますが、実際のアプリにとっては害以上の助けになります。キャッシュレイヤーなどを統合するための優れたシームレスな方法を見つけない限り、テストが難しくなり、パフォーマンスが低下します。この時点で、通常は View または TemplateView から継承して、それで完了です。

特に DB モッキングに関しては、モックを作成し、ビジネス ロジックを調べます。次に、特定のルールとインターフェースのセットに準拠している限り、何を入力/出力しているかは問題ではありません。たとえば、 Mixerのようなものを参照してください。テスト中に一時 DB を作成/破棄することもできます。1 つの方法は、dev/staging/production/testing などの個別の設定モジュールを作成し、環境に応じて動的にロードすることです。そうすれば、単体テストを実行するときに、作業中の開発データベースが損傷するのを防ぐことができます。もちろん、これは統合テストの形式にさらに移行していますが、おそらくその一部も行う必要があります。前述のソリューションは、Hibernate などの他の ORM で一般的です。

前に関連して、設定で以下のコードのようなことを実行して、単体テストにメモリ内データベースを使用できます。ただし、最終的には、MySQL などの実際のデータ ストア タイプに対する統合テストを検討する必要があります。

if 'test' in sys.argv:
    DATABASES['default']['ENGINE'] = 'sqlite3'

;tldr

  1. ロジックをクラス ビューの外に配置し、適切なオブジェクトとモジュールに配置します。

  2. バンドルされているさまざまなクラスベースのビューを、実際のアプリやすべてのユース ケースで機能させることに固執しないでください。自分で巻きます。

  3. IOC などの一般的に適切な TDD 原則を使用し、必要なパラメーターをコンストラクターに渡し、物事を疎結合し、過剰な独自の状態要件 (特に HTTP) を回避します。

    1. 標準のモック オブジェクトを作成し (#3 を参照)、サービスのようなインターフェイスを使用することで (#1 を参照)、DB への依存を回避します。
于 2014-03-17T08:47:10.520 に答える