Nodejs学習ノートのテスト駆動
5462 ワード
第2章では、テストドライバについて説明します.ここのテストは主にWebバックエンドのテストに対して――あなたはどうしてテスト用例(つまりテスト用例の完備が時間の浪費であるかどうか)、どのようにあなたのテスト用例を完備して、コード設計はどのようにテスト用例の書くことを簡略化して、およびいくつかの後期の構想を書きます.
1.なぜテストケースを書くのか
この習慣は通常、開発の進捗を遅らせる行為とされ、開発コードとほぼ同じ時間を費やしてテスト例を徐々に改善する必要があります.しかし、開発の過程で、コードの開発が完了した後、完全に問題をテスト担当者に任せるのではなく、責任を持って発見すれば、この時は通常手動のテストをします.例:
コードでいくつかのメソッドを実行し、出力の値が予想に合っているかどうかを確認します.データベース/キャッシュを変更し、データベースの変化が予想に合致するかどうかを確認する方法を実行します.ツールシミュレーションを使用して、一部のインタフェースを要求し、インタフェースの戻り値/データベースの変化値が予想に合致するかどうかを確認します.フロントエンドページがある場合は、フロントエンドページでフロントエンドインタラクションを行い、フロントエンドのフィードバックが予想に合致しているかどうかを確認し、バックエンドコードの正確性を間接的に検証する前後エンドインターフェースにも関連します.近代的なテストツールは、これらの人工的な手動テスト動作をできるだけコードブロックに抽象化しており、手動テストを意識しているときに、実際にはテスト例の動作を試しています.手動でテストできる以上、なぜコードでテストを実現する必要があるのでしょうか.
コードは多重化したり、簡単に再構築したりしてより多くの機能を実現することができますが、手動を選択するたびに、最初からやり直す必要があります.成熟したワークフローには、コード監査プロセスが含まれている必要があります.コード監査の方法はたくさんあります.あなたのコードを文ごとに読むか、テストコードの完備性と正確性をチェックして、テスト例を実行します.後者はもっと簡単です.バグを修正するなど、コードの変更が他のコードに依存する部分に影響を及ぼすかどうかを保証するのは難しい.人工テストの時代には回帰テストというものがあります.つまり、Bugを修復してシステムを再テストします.しかし、もしあなたがすでに完璧なテスト例を持っているなら、直接コマンドを実行してください.コードを再構築するときは、同じです.
2.どのようにあなたのテスト用例を改善するか
完全な段階に入る前に、テスト例をどのように実現するかについてお話しします.
上のコードはRubyのminitestから来ています.beforeに含まれるコードブロックは、次のテスト・インスタンスを実行する前に行うことであり、通常、テスト・インスタンスの実行が完了するまで、対応する方法もサポートされます.各用例には小さな判断が行われている.
第1段では、手動テストでよく使われるテスト内容について説明します.ここでは、その中の2と3を説明します.データベース関連のテストを行う場合は、beforeにテストデータを挿入し、afterでテストデータを削除する必要があります.中間の試験例では、対応する方法を実行することによって、実行が完了した後、データの変化状況を確認したり、予想される異常があるかどうかを確認したり、予想された結果を返したりすることで、コードの正確性を確認します.インタフェースであれば、コードで対応するリクエストを開始し、返された内容が予想を返すかどうかを確認し、必要に応じてデータベース内のデータが予想に合っているかどうかを確認します.
現在、テスト例がありますが、特別な状況を考慮する必要があります.私は今1つの関数のために比較的に完備したテスト用例を書いて、走ってすべてPASSを走って、結果はオンラインのログの中でやはりその関数の報告が間違っていることを発見しました.チェックして関数のあるブランチを発見する前にテストしていないで、ちょうど線上のある状況でこのブランチを実行して、結果は1つのとても明らかではない文法の間違いが間違って報告して、すべてのコードがすべてテストしたことを確保することができますか?ここで導入する必要があるのは,テスト用例のカバー率という概念であり,基本的に各言語が応答して実現される.テスト例のカバー率を通じて、あなたのテスト例が○○ファイルのすべてのコードを走ったかどうかを量子化して教えます.あなたがしなければならないのは、できるだけカバー率を100%に保つことです.
ある意味では、テスト例とテストオーバーライド率は、開発者のコードに対する自信を高めるためのツールです.しかし、彼らも万能ではない.テスト用例の中でいつもいくつかのパラメータの可能性を漏らす可能性があります.もちろん、あなたのコードの中にもこのような可能性のためにコードの作成を行っていません.最終的なテスト用例のカバー率はあなたが書いたコードを教えてあげるしかありません.私たちはあなたがテストしたことを検出しました.あなたが考慮していない可能性に対して、何もできません.したがって、javascriptではできるだけ===ではなく===を使用したり、強いタイプのプログラミング仕様を使用したりするなど、厳格なコードをできるだけ作成し、受け入れられるパラメータの範囲が大きすぎるため、潜在的なリスクを低減します.
3.コード設計はどのようにテスト用例の書き方を簡略化するか
Web全体(Webに限らない)は、単純なデータ処理と演算、データベース、具体的なネットワークプロトコルの3つのレベルのコードを含むことが多い.その中で単純なデータ演算は主に一般的な演算を処理する関数や他のコードに関連し、データベースに関連するのは伝統的な意味でMVCの中のMであり、具体的なネットワークプロトコルに関連するのは対応するCである.この3つのブロックのテストは、第1節の通常のテスト内容の最初の3つに対応している.
Cレベルでは通常、ページのレンダリングや対応するプロトコルのシミュレーションにも関与する可能性があるため、テストの重心を関数やデータベース関連のコードに置くことで、テスト用例コードの複雑さを減らすことができ、Controllerのコードをできるだけ少なくする必要があります.複雑度の高いアプリケーションに関する現在のいくつかの提案:
データの基礎チェックをすべてM層に置き、Ruby開発を使えばActiveRecordやMongoidが使いやすいvalidation機能を提供しています.Model間の通信を実現するために、いくつかのORMで提供されているフック(hook)と組み合わせたPub/subモードをコードで使用することを試みた.例えば、Aが作成されたときにメッセージを発行し、Bはメッセージを監視した後、自分の属性値を変更する.Commandモードを使用して、メール送信など、ビジネスに関係のない機能をシステムから抽出します.以上の推奨リファレンス:Laravel wisper resque
4.構想
以上の内容はいずれも前後端で連調する必要がある試験例を避け,以下の内容は主にこれに対するものである.ルビーはこの方向にいくつかの優雅な実現があり、興味のある人は直接Capybaraを鑑賞することができます.
Selenium Phantomjsや前者ベースのWatirなど一連のブラウザドライバの普及に伴い,コード制御ブラウザの使用はもはや複雑なことではない.この能力に基づいて、フロントエンドベースのテストを4つのステップに分けてみることができます.
ユーザー操作をシミュレートするフラグ要素の出現(例えば、ページの読み込み待ち、またはコンテンツの非同期ロードの出現)を待つ.ここでの操作には、ユーザークリック、ユーザー入力待ちフィードバックにおけるフラグ要素の出現(例えば、○○入力ボックスの出現)の判断内容が含まれ、予想に合致するかどうかがこのプロセスに基づいて、ほとんどのフロントエンドテストを解決することができる.しかし、このプロセスだけでは不十分です.ページに検証コードのような障害要素が現れる可能性があるため、コードを変更しない前提で、データベース/キャッシュでこれらの内容を取得しようとすることができます.同様に、テストインタフェースと同様に、ここではテスト前のデータベースにテストデータを挿入し、テスト例の実行後に深刻なデータベース内のデータの変化、およびすべてのテストが完了した後にテストデータを削除する内容についても触れます.最終的に、このテスト・インスタンス・コードの実装には、フロントエンド・バックエンドの理解が必要になります.現在、Capybaraを参考にして、より汎用的な案を設計することも考えられています.
最後にCapybaraのコードを貼って、この内容を終了します.
1.なぜテストケースを書くのか
この習慣は通常、開発の進捗を遅らせる行為とされ、開発コードとほぼ同じ時間を費やしてテスト例を徐々に改善する必要があります.しかし、開発の過程で、コードの開発が完了した後、完全に問題をテスト担当者に任せるのではなく、責任を持って発見すれば、この時は通常手動のテストをします.例:
コードでいくつかのメソッドを実行し、出力の値が予想に合っているかどうかを確認します.データベース/キャッシュを変更し、データベースの変化が予想に合致するかどうかを確認する方法を実行します.ツールシミュレーションを使用して、一部のインタフェースを要求し、インタフェースの戻り値/データベースの変化値が予想に合致するかどうかを確認します.フロントエンドページがある場合は、フロントエンドページでフロントエンドインタラクションを行い、フロントエンドのフィードバックが予想に合致しているかどうかを確認し、バックエンドコードの正確性を間接的に検証する前後エンドインターフェースにも関連します.近代的なテストツールは、これらの人工的な手動テスト動作をできるだけコードブロックに抽象化しており、手動テストを意識しているときに、実際にはテスト例の動作を試しています.手動でテストできる以上、なぜコードでテストを実現する必要があるのでしょうか.
コードは多重化したり、簡単に再構築したりしてより多くの機能を実現することができますが、手動を選択するたびに、最初からやり直す必要があります.成熟したワークフローには、コード監査プロセスが含まれている必要があります.コード監査の方法はたくさんあります.あなたのコードを文ごとに読むか、テストコードの完備性と正確性をチェックして、テスト例を実行します.後者はもっと簡単です.バグを修正するなど、コードの変更が他のコードに依存する部分に影響を及ぼすかどうかを保証するのは難しい.人工テストの時代には回帰テストというものがあります.つまり、Bugを修復してシステムを再テストします.しかし、もしあなたがすでに完璧なテスト例を持っているなら、直接コマンドを実行してください.コードを再構築するときは、同じです.
2.どのようにあなたのテスト用例を改善するか
完全な段階に入る前に、テスト例をどのように実現するかについてお話しします.
describe Meme do
before do
@meme = Meme.new
end
describe "when asked about cheeseburgers" do
it "must respond positively" do
@meme.i_can_has_cheezburger?.must_equal "OHAI!"
end
end
describe "when asked about blending possibilities" do
it "won't say no" do
@meme.will_it_blend?.wont_match /^no/i
end
end
end
上のコードはRubyのminitestから来ています.beforeに含まれるコードブロックは、次のテスト・インスタンスを実行する前に行うことであり、通常、テスト・インスタンスの実行が完了するまで、対応する方法もサポートされます.各用例には小さな判断が行われている.
第1段では、手動テストでよく使われるテスト内容について説明します.ここでは、その中の2と3を説明します.データベース関連のテストを行う場合は、beforeにテストデータを挿入し、afterでテストデータを削除する必要があります.中間の試験例では、対応する方法を実行することによって、実行が完了した後、データの変化状況を確認したり、予想される異常があるかどうかを確認したり、予想された結果を返したりすることで、コードの正確性を確認します.インタフェースであれば、コードで対応するリクエストを開始し、返された内容が予想を返すかどうかを確認し、必要に応じてデータベース内のデータが予想に合っているかどうかを確認します.
現在、テスト例がありますが、特別な状況を考慮する必要があります.私は今1つの関数のために比較的に完備したテスト用例を書いて、走ってすべてPASSを走って、結果はオンラインのログの中でやはりその関数の報告が間違っていることを発見しました.チェックして関数のあるブランチを発見する前にテストしていないで、ちょうど線上のある状況でこのブランチを実行して、結果は1つのとても明らかではない文法の間違いが間違って報告して、すべてのコードがすべてテストしたことを確保することができますか?ここで導入する必要があるのは,テスト用例のカバー率という概念であり,基本的に各言語が応答して実現される.テスト例のカバー率を通じて、あなたのテスト例が○○ファイルのすべてのコードを走ったかどうかを量子化して教えます.あなたがしなければならないのは、できるだけカバー率を100%に保つことです.
ある意味では、テスト例とテストオーバーライド率は、開発者のコードに対する自信を高めるためのツールです.しかし、彼らも万能ではない.テスト用例の中でいつもいくつかのパラメータの可能性を漏らす可能性があります.もちろん、あなたのコードの中にもこのような可能性のためにコードの作成を行っていません.最終的なテスト用例のカバー率はあなたが書いたコードを教えてあげるしかありません.私たちはあなたがテストしたことを検出しました.あなたが考慮していない可能性に対して、何もできません.したがって、javascriptではできるだけ===ではなく===を使用したり、強いタイプのプログラミング仕様を使用したりするなど、厳格なコードをできるだけ作成し、受け入れられるパラメータの範囲が大きすぎるため、潜在的なリスクを低減します.
3.コード設計はどのようにテスト用例の書き方を簡略化するか
Web全体(Webに限らない)は、単純なデータ処理と演算、データベース、具体的なネットワークプロトコルの3つのレベルのコードを含むことが多い.その中で単純なデータ演算は主に一般的な演算を処理する関数や他のコードに関連し、データベースに関連するのは伝統的な意味でMVCの中のMであり、具体的なネットワークプロトコルに関連するのは対応するCである.この3つのブロックのテストは、第1節の通常のテスト内容の最初の3つに対応している.
Cレベルでは通常、ページのレンダリングや対応するプロトコルのシミュレーションにも関与する可能性があるため、テストの重心を関数やデータベース関連のコードに置くことで、テスト用例コードの複雑さを減らすことができ、Controllerのコードをできるだけ少なくする必要があります.複雑度の高いアプリケーションに関する現在のいくつかの提案:
データの基礎チェックをすべてM層に置き、Ruby開発を使えばActiveRecordやMongoidが使いやすいvalidation機能を提供しています.Model間の通信を実現するために、いくつかのORMで提供されているフック(hook)と組み合わせたPub/subモードをコードで使用することを試みた.例えば、Aが作成されたときにメッセージを発行し、Bはメッセージを監視した後、自分の属性値を変更する.Commandモードを使用して、メール送信など、ビジネスに関係のない機能をシステムから抽出します.以上の推奨リファレンス:Laravel wisper resque
4.構想
以上の内容はいずれも前後端で連調する必要がある試験例を避け,以下の内容は主にこれに対するものである.ルビーはこの方向にいくつかの優雅な実現があり、興味のある人は直接Capybaraを鑑賞することができます.
Selenium Phantomjsや前者ベースのWatirなど一連のブラウザドライバの普及に伴い,コード制御ブラウザの使用はもはや複雑なことではない.この能力に基づいて、フロントエンドベースのテストを4つのステップに分けてみることができます.
ユーザー操作をシミュレートするフラグ要素の出現(例えば、ページの読み込み待ち、またはコンテンツの非同期ロードの出現)を待つ.ここでの操作には、ユーザークリック、ユーザー入力待ちフィードバックにおけるフラグ要素の出現(例えば、○○入力ボックスの出現)の判断内容が含まれ、予想に合致するかどうかがこのプロセスに基づいて、ほとんどのフロントエンドテストを解決することができる.しかし、このプロセスだけでは不十分です.ページに検証コードのような障害要素が現れる可能性があるため、コードを変更しない前提で、データベース/キャッシュでこれらの内容を取得しようとすることができます.同様に、テストインタフェースと同様に、ここではテスト前のデータベースにテストデータを挿入し、テスト例の実行後に深刻なデータベース内のデータの変化、およびすべてのテストが完了した後にテストデータを削除する内容についても触れます.最終的に、このテスト・インスタンス・コードの実装には、フロントエンド・バックエンドの理解が必要になります.現在、Capybaraを参考にして、より汎用的な案を設計することも考えられています.
最後にCapybaraのコードを貼って、この内容を終了します.
feature "Signing in" do
background do
User.make(:email => '[email protected]', :password => 'caplin')
end
scenario "Signing in with correct credentials" do
visit '/sessions/new'
within("#session") do
fill_in 'Email', :with => '[email protected]'
fill_in 'Password', :with => 'caplin'
end
click_button 'Sign in'
expect(page).to have_content 'Success'
end
given(:other_user) { User.make(:email => '[email protected]', :password => 'rous') }
scenario "Signing in as another user" do
visit '/sessions/new'
within("#session") do
fill_in 'Email', :with => other_user.email
fill_in 'Password', :with => other_user.password
end
click_button 'Sign in'
expect(page).to have_content 'Invalid email or password'
end
end