8

私が取り組んでいるプロジェクトは、Pythonパッケージとしてラップされたビジネスロジックソフトウェアです。アイデアは、さまざまなスクリプトまたはアプリケーションがそれをインポートし、初期化してから使用するというものです。

現在、初期化を行い、さまざまなことを設定するトップレベルのinit()メソッドがあります。良い例は、db接続を使用してSQLAlchemyを設定し、後でアクセスできるようにSAセッションを保存することです。これは、私のプロジェクトのサブパッケージ(つまり、myproj.model.Session)に格納されているため、モデルをインポートした後、他のコードが機能するSAセッションを取得できます。

簡単に言えば、これは私のパッケージをステートフルなものにします。私はプロジェクトの単体テストを書いていますが、この安定した動作にはいくつかの問題があります。

  1. テストは分離する必要がありますが、私のパッケージの内部状態はこの分離を破ります
  2. メインのinit()メソッドの動作は状態に依存するため、テストできません。
  3. 将来のテストは、よく知られているモデル状態(たとえば、事前に入力されたsqlite インメモリデータベース)を持つ(まだ書き込まれていない)コントローラー部分に対して実行する必要があります。

現在の構造はBest(possible)Practice(tm)ではないため、どういうわけかパッケージをリファクタリングする必要がありますか?:)

それをそのままにして、毎回すべてをセットアップ/ティアダウンする必要がありますか?完全な分離を実現する場合、つまり、すべてのテストでデータベースを完全に消去して再入力することを意味しますが、それはやり過ぎではありませんか?

この質問は、実際には全体的なコードとテストの構造に関するものですが、その価値については、テストにnose-1.0を使用しています。Isolateプラグインがおそらく役立つことはわかっていますが、テストスイートで奇妙なことをする前にコードを取得したいと思います。

4

3 に答える 3

3

いくつかのオプションがあります:

データベースをモックする

注意すべきトレードオフがいくつかあります。

接続のセットアップ、ティアダウン、およびモックを行う必要があるため、テストはより複雑になります。送信された SQL/コマンドの検証を行うこともできます。また、スキーマまたは SQL が変更されたときに、テストの保守/更新に余分な時間を費やす原因となる奇妙な種類の密結合を作成する傾向があります。

これは、テストから潜在的に大きな依存関係を減らすため、通常、テスト分離の最も純粋な方法です。また、テストを高速化する傾向があり、継続的インテグレーション環境などでテスト スイートを自動化するためのオーバーヘッドを削減します。

各テストで DB を再作成します

注意すべきトレードオフ。

これにより、データベースの再作成に実際にかかる時間によっては、テストが非常に遅くなる可能性があります。dev データベース サーバーが共有リソースである場合、各 dev がサーバー上に独自のデータベースを持っていることを確認するために、追加の初期投資が必要になります。テストの実行頻度によっては、サーバーが影響を受ける可能性があります。継続的インテグレーション環境でテスト スイートを実行すると、追加のオーバーヘッドが発生します。これは、少なくとも、場合によってはより多くのデータベースが必要になるためです (同時に構築されるブランチの数によって異なります)。

この利点は、本番環境で使用されるのと同じコード パスと同様のリソースを実際に実行することに関係しています。これは通常、バグを早期に明らかにするのに役立ちます。これは常に非常に良いことです。

ORM DB スワップ

SQLAlchemy のような ORM を使用している場合は、基礎となるデータベースを潜在的に高速なメモリ内データベースと交換できる可能性があります。これにより、前の両方のオプションの欠点の一部を軽減できます。

これは本番環境で使用されるデータベースとまったく同じではありませんが、ORM はバグを覆い隠すリスクを軽減するのに役立つはずです。通常、インメモリ データベースをセットアップする時間は、ファイルに基づくデータベースよりもはるかに短くなります。また、現在のテスト実行に分離されるという利点もあるため、共有リソースの管理や最終的な分解/クリーンアップについて心配する必要はありません。

于 2011-04-17T05:09:21.070 に答える
1

比較的高価なセットアップ (IPython) を使用するプロジェクトに取り組んでいるときにget_ipython、インスタンスをセットアップして返す関数を呼び出し、それ自体を既存のインスタンスへの参照を返す関数に置き換えるというアプローチが使用されているのを見てきました。次に、すべてのテストで同じ関数を呼び出すことができますが、最初のテストのセットアップのみを行います。

これにより、すべてのテストで長いセットアップ手順を実行する必要がなくなりますが、以前に実行されたテストに応じて、テストが失敗または成功するという奇妙なケースが発生することがあります。これに対処する方法があります。多くのテストは状態に関係なく同じことを行う必要があり、特定のテストの前にオブジェクトの状態をリセットすることができます。同様のトレードオフが機能する場合があります。

于 2011-04-15T11:53:51.303 に答える
0

Mockは、ある程度の分離を実現するためのシンプルで強力なツールです。それを使用する方法を示す Pycon2011 からの素晴らしいビデオがあります。テストを定義するために必要なコードの量を減らし、それでも非常に強力な py.test と一緒に使用することをお勧めします。

于 2011-04-15T12:53:24.130 に答える