djangoとpostgresでTDDを実装する

Ostrovkaには、ユーザー向け(ostrovok.ru)とホテル向けの「管理者」 (エクストラネット)という2つの主要な製品があり、ここで署名したホテルがデータを入力します。 これらは独自のチームであり、テストによる開発(TDD)に対する態度が異なります。 同じプラットフォーム:djangoとpostgres。 彼らはエクストラネットでTDDを使用し、多数のテストを行っています。 当初、テストはostrovok.ruにもありましたが、エクストラネットの一部の支持者の離脱と非常に集中的な開発のため、サポートを中止しました。 一般に、テストを実装するという課題に直面しました。 最初のステップが完了しました。この経験と適用されたソリューションを共有したいと思います。

QAとSeleniumの自動テスト部門がありますが、これは別です。



djangoとテストでは、一般的に物事はかなり良いです。もちろん、最初からすべてをテストでカバーし、機能を増やし、リファクタリングを行う方が良いでしょう。



私たちの場合、巨大な機能と多くの包括的な依存関係と外部APIとの統合がすでに存在していました。 また、テスト環境で動作するために必要です。 メモリ内の高速SQLiteを忘れることができます。プロジェクトにはpostgresの機能へのバインドがあり、テスト環境のIDは依然として重要なので、テストはpostgresでも機能します。





私が好きなテストとTDDの理由





さまざまな側面で異なる多くの種類のテストがあります。



単独では、統合テストの方が好きで、テスト対象のオブジェクトでは機能テストが好きです。



このようなテストには、非常に大きなコードカバレッジがあり、同時にプラスとマイナスの両方になります。



マイナス:



長所:





私たちはウェブを開発していますが、理想的にはブラウザを開いてコードを手動でテストしたくないのです。 ブラウザー内のすべてのアクションをテストに書き留めて、いくつかのチェックを追加します(データベース内の文字、ログまたは何らかのオブジェクトの送信)。 コードを作成するとき、これらのすべてのアクションを確実に1回手動で実行する必要がありますが、ほとんどの場合、それは数回になります。 テストにアクションを書き込み、数秒で10回実行することは、手動で10回チェックするよりもはるかにクールです。 ブラウザーでは、メインマークアップ、スタイル、画像、javascriptも読み込まれ、これらすべては通常ローカルランサーバーに分類されますが、最も賢くはなく、多くの場合1つのスレッドで動作します。 開発用にたくさんのuwsgiとnginxをセットアップする気はありません。さらに、開発に役立ったテストリグレッションテストに残り、重要な役割を果たすという利点もあります



httpリクエストのテストに加えて、たとえばdjangoコマンドのテストなど、他のテストもありますが、それらはすべて同じです。 従来の単体テストも役立ちます。 テストの実行と作成に慣れると、開発スタイルが変わり、プロセスが反復される可能性が高くなります。単純なテスト-必要なコード、テストを複雑にします-コードを追加します。 たとえば、タイプミスをして、テストをすばやく実行し、タイプミスとテストがパスしなかったことを確認できます。



そしてもちろん、手動テストが難しい、またはほとんど不可能な場所もあり、その場合はテストが必要です。 例:例外の正しいキャッチとエラー処理、繊細なロジックの場所の確認...



理想的には、最初にテストを行います。



テストによる開発のすべての利点を説明することは、この記事の目的ではなく、他の人、たとえばKent Beckに任せます。



実行中のテストを高速化する方法は?



TDDでは、テストを実行することが非常に重要な操作です。 通常、これはすべてのテストでさえありませんが、パッケージのテスト、個別のモジュール、さらには個別のテストなど、ある種のセットです。 したがって、個々のテストケースの立ち上げは迅速でなければなりません。



djangoでは、これは問題であり 、各テスト実行の前にデータベースを作成します。回路が大きい場合、30秒かかることがあり、特定のテストにかかる時間は1秒未満です。 ベースが作成されるまで待ちたくありません。



解決策:別の手順でデータベースを作成します(以前の実行のデータベースを使用します)。



この条件下では、基本スキームに加えて、初期データも必要でした:





新機能のようです:





既存のコードを使用してください!





「テストなし」の時間に、ホテルの輸入に関連するメガリファクタリングに参加しなければなりませんでした。 このタスクの過程で、インポートを適切にカバーするテストが行​​われました。 これらのテストは寿命を延ばしましたが、ほとんどが削除された他の既存のテストのように、それらが無駄にならないように最新の状態に保ちました。



繰り返しになりますが、ホテルは複雑なエンティティであり、接続されたすべてのオブジェクトを作成し、この経済をすべてサポートしたくありませんでした。 さらに、機能するテスト済みのインポートコードがあり、そのタスクはホテルを作成するだけであり、接続されています。 コードが少ないほどエラーが少なくなります。



noseを使用してテストを実行します。一般に、プラグインをサポートしてテストを実行するための非常に優れたツールです。



その結果、 独自のランナーといくつかの問題を解決する多くのプラグインを入手しました。











コマンドラインパラメータに応じて、データベースを作成するプロセスがあります。



... --with-reuse-db #   ,     --create-db #       ...
      
      







このアプローチにはマイナス面があります。ベーススキームが変更された場合、ベースを再作成する必要があることを覚えておく必要があります。 これは重要ではなく、クイックスタートよりも重要です。



GISおよびホテルをインポートする場合、最初のベースを作成するプロセスはすでに1分ほどかかります。 さらに、ホテルがある場合とない場合の2つの初期ベースを維持します。 輸入をテストするとき、ホテルは必要ありません。 特定のTestCase



では、必要なベーステンプレートを設定します。



標準のdjangoアプローチでは、 flush



TransactionTestCaseから行われ(完全なデータベースクリーンアップ)、最初のものが復元されます。 このアプローチは機能しません、なぜなら ベースを作成するための別のステップがあり、それをきれいにする必要はありません。 postgres自動コミットオプションは、すべてのテストでflush



実行されましたが、それは悪いことです-それは長いです。



flush



に関して)テストを高速化するために、テンプレートに従って作成された一意のデータベースを使用しました。postgresはこれを実行できます。



 src = self.db_conf['TEST_NAME'] new = '{0}_{1}'.format(src, uuid.uuid4().hex) psql( 'DROP DATABASE IF EXISTS "{0}";' 'CREATE DATABASE "{0}" WITH TEMPLATE "{1}";' .format(new, src) )
      
      





数回の増加は比較的数回あり、かなり良いようでした。 独自のテストベースの利点は、データベース内の一部の衝突の可能性がゼロであり、トランザクションを使用することで可能になることです。 最終的に、彼らはオプションに来ました:デフォルトでは、トランザクションで動作します、なぜなら より高速であり、一部のテストに問題がある場合は、独自のベースになります。

テストベースを高速化するために、postgresql.confに置くこともできます。

 fsync = off # turns forced synchronization on or off
      
      





増加も感じられます。 まあ、SSDドライブも良いです:)。





このようなテストは、アセンブリプロセスに含めるのが簡単で、十分にすばやく(3〜4分〜250テスト)合格し、リリースを大幅に遅らせることなく、コードの隣にあります。 次のように、テストの実行を高速化するために監視および対策を講じる必要があります。 テストの数は増加するだけで、実行時間を意味します。



さらに加速に関しては、テストの起動を並列化する必要があり、 noseはその方法も知っていますが、コードを改良する必要があります。



テストをすばやく実行することに加えて、自発的にテストを作成する必要もあります。 多数の包括的な依存関係がある場合、ユーザーの基本的なアクションを繰り返す最初のテストは困難です。 多くの場所をカバーする必要があり、多くの場所を把握する必要があります。 したがって、最小限のコードでこのようなテストの作成を簡素化するためのアシスタントを作成する時間が割り当てられました。



何がありますか?



テストが大幅に高速化されたため、パッケージのアセンブリに関係するようになりました。テストが失敗した場合、リリースはロールアウトされません。 これも非常に重要なポイントです。なぜなら 明確な関連性があります:動作テスト-リリース、非動作テスト-リリースなし(頻繁なリリースがあり、1日に数回あります)。 セレンの自動テストはまだ別の生活を送っていますが、チームは継続的な統合のプロセスにそれらを含めることに取り組んでいます。



テストはすでに役立ちます:









原則として、開始が行われ、決定が行われ、次に何が起こるか-時間はわかります。



PS pythonpostgresは素晴らしいツールです-使用してください。



投稿者: naspeh



All Articles