apeescape2.com
  • メイン
  • Uiデザイン
  • アジャイル
  • 技術
  • 仕事の未来
バックエンド

統合テストを実際に行うためのNode.jsガイド

統合テストは恐ろしいものではありません。これらは、アプリケーションを完全にテストするための重要な部分です。

テストについて話すとき、私たちは通常、コードの小さなチャンクを分離してテストする単体テストについて考えます。ただし、アプリケーションはその小さなコードチャンクよりも大きく、アプリケーションのほとんどの部分が単独で機能しません。これは、統合テストがその重要性を証明する場所です。統合テストは、単体テストが不十分な場所をピックアップし、単体テストとエンドツーエンドテストの間のギャップを埋めます。

統合テストを作成する必要があることを知っているのに、なぜそれを行わないのですか? つぶやき

この記事では、APIベースのアプリケーションの例を使用して、読み取り可能で構成可能な統合テストを作成する方法を学習します。



JavaScript /を使用しますが Node.js この記事のすべてのコード例について、説明したほとんどのアイデアは、任意のプラットフォームでの統合テストに簡単に適合させることができます。

単体テストと統合テスト:両方が必要

単体テストは、特定のコード単位に焦点を当てています。多くの場合、これは特定の方法またはより大きなコンポーネントの機能です。

これらのテストは個別に実行され、通常、すべての外部依存関係がスタブまたはモックされます。

つまり、依存関係は事前にプログラムされた動作に置き換えられ、テストの結果がテスト対象のユニットの正確さによってのみ決定されるようにします。

あなたはユニットテストについてもっと学ぶことができます ここに 。

単体テストは、優れた設計で高品質のコードを維持するために使用されます。また、コーナーケースを簡単にカバーすることもできます。

ただし、欠点は、単体テストではコンポーネント間の相互作用をカバーできないことです。ここで統合テストが役立ちます。

統合テスト

単体テストがコードの最小単位を分離してテストすることによって定義されている場合、統合テストは正反対です。

統合テストは、相互作用する複数のより大きなユニット(コンポーネント)をテストするために使用され、場合によっては複数のシステムにまたがることもあります。

統合テストの目的は、次のようなさまざまなコンポーネント間の接続と依存関係のバグを見つけることです。

  • 無効または誤った順序の引数を渡す
  • 壊れたデータベーススキーマ
  • 無効なキャッシュ統合
  • ビジネスロジックの欠陥またはデータフローのエラー(テストはより広い視野から行われるようになったため)。

テストしているコンポーネントに複雑なロジックがない場合(例:最小限のコンポーネント 循環的複雑度 )、統合テストは単体テストよりもはるかに重要になります。

この場合、単体テストは主に優れたコード設計を実施するために使用されます。

単体テストは関数が適切に記述されていることを確認するのに役立ちますが、統合テストはシステムが全体として適切に機能していることを確認するのに役立ちます。したがって、単体テストと統合テストはそれぞれ独自の補完的な目的を果たし、包括的なテストアプローチには両方が不可欠です。

ユニットテストと統合テストは、同じコインの両面のようなものです。コインは両方なしでは無効です。

したがって、統合テストと単体テストの両方を完了するまで、テストは完了しません。

統合テスト用のスイートをセットアップする

単体テスト用のテストスイートのセットアップは非常に簡単ですが、統合テスト用のテストスイートのセットアップは多くの場合より困難です。

たとえば、統合テストのコンポーネントには、データベース、ファイルシステム、電子メールプロバイダー、外部支払いサービスなど、プロジェクト外の依存関係があります。

場合によっては、統合テストでこれらの外部サービスとコンポーネントを使用する必要があり、スタブ化されることもあります。

それらが必要な場合、それはいくつかの課題につながる可能性があります。

  • 壊れやすいテストの実行: 外部サービスが利用できない、無効な応答を返す、または無効な状態になっている可能性があります。場合によっては、これが誤検知になることもあれば、誤検知になることもあります。
  • 実行が遅い: 外部サービスの準備と接続に時間がかかる場合があります。通常、テストはの一部として外部サーバーで実行されます CI 。
  • 複雑なテストセットアップ: 外部サービスは、テストに必要な状態である必要があります。たとえば、データベースには必要なテストデータなどをプリロードする必要があります。

統合テストを作成する際に従うべき指示

統合テストには、次のような厳密なルールはありません。 ユニットテスト 。それにもかかわらず、統合テストを作成するときに従うべきいくつかの一般的な指示があります。

繰り返し可能なテスト

テストの順序や依存関係によってテスト結果が変わることはありません。同じテストを複数回実行すると、常に同じ結果が返されます。テストでインターネットを使用してサードパーティのサービスに接続している場合、これを実現するのは難しい場合があります。ただし、この問題はスタブとモックで回避できます。

より細かく制御できる外部依存関係の場合、統合テストの前後に手順を設定すると、テストが常に同じ状態から開始して実行されるようになります。

モンテカルロシミュレーション時系列

関連するアクションのテスト

考えられるすべてのケースをテストするには、単体テストがはるかに優れたオプションです。

統合テストは、モジュール間の接続に重点を置いているため、テスト 幸せなシナリオ モジュール間の重要な接続をカバーするため、通常はこれが最適な方法です。

わかりやすいテストとアサーション

テストの1つのクイックビューは、何がテストされているか、環境がどのようにセットアップされているか、何がスタブされているか、いつテストが実行されているか、何がアサートされているかを読者に通知する必要があります。アサーションは単純で、比較とロギングを改善するためにヘルパーを利用する必要があります。

簡単なテストセットアップ

テストを初期状態にすることは、可能な限り単純で理解しやすいものでなければなりません。

サードパーティのコードのテストは避けてください

テストではサードパーティのサービスを使用できますが、テストする必要はありません。そして、あなたがそれらを信頼しないのなら、あなたはおそらくそれらを使うべきではありません。

プロダクションコードをテストコードなしのままにする

プロダクションコードはクリーンでわかりやすいものにする必要があります。 テストコードと製品コードの混合 接続できない2つのドメインが結合されます。

関連するロギング

失敗したテストは、適切なログがなければあまり価値がありません。

テストに合格すると、追加のログは必要ありません。しかし、それらが失敗した場合、広範なロギングが不可欠です。

ロギングには、すべてのデータベースクエリ、APIリクエストとレスポンス、およびアサートされているものの完全な比較が含まれている必要があります。これにより、デバッグが大幅に容易になります。

良いテストはきれいでわかりやすいように見えます

ここでのガイドラインに従う簡単なテストは、次のようになります。

const co = require('co'); const test = require('blue-tape'); const factory = require('factory'); const superTest = require('../utils/super_test'); const testEnvironment = require('../utils/test_environment_preparer'); const path = '/v1/admin/recipes'; test(`API GET ${path}`, co.wrap(function* (t) { yield testEnvironment.prepare(); const recipe1 = yield factory.create('recipe'); const recipe2 = yield factory.create('recipe'); const serverResponse = yield superTest.get(path); t.deepEqual(serverResponse.body, [recipe1, recipe2]); }));

上記のコードは、保存されたレシピの配列を応答として返すことを期待するAPI(GET /v1/admin/recipes)をテストしています。

テストは、単純なものであっても、多くのユーティリティに依存していることがわかります。これは、優れた統合テストスイートに共通しています。

ヘルパーコンポーネントを使用すると、わかりやすい統合テストを簡単に作成できます。

統合テストに必要なコンポーネントを確認しましょう。

ヘルパーコンポーネント

包括的なテストスイートには、フロー制御、テストフレームワーク、データベースハンドラー、バックエンドAPIへの接続方法などのいくつかの基本的な要素が含まれています。

フロー制御

JavaScriptテストの最大の課題の1つは、非同期フローです。

コールバックはできます 大混乱をもたらす コードと約束では十分ではありません。ここでフローヘルパーが役立ちます。

待っている間 非同期/待機 完全にサポートされるために、同様の動作を持つライブラリを使用できます。目標は、非同期フローを持つ可能性のある、読みやすく、表現力があり、堅牢なコードを作成することです。

何 コードをブロックしないようにしながら、コードを適切に記述できるようにします。これは、coジェネレーター関数を定義し、結果を生成することによって行われます。

別の解決策は使用することです 青い鳥 。 Bluebirdは、配列、エラー、時間などの処理などの非常に便利な機能を備えたPromiseライブラリです。

CoとBluebirdのコルーチンは、ES7のasync / awaitと同様に動作します(続行する前に解決を待機します)。唯一の違いは、エラーの処理に役立つpromiseを常に返すことです。

テストフレームワーク

テストフレームワークの選択は、個人的な好みに帰着します。私の好みは、使いやすく、副作用がなく、出力が読みやすく、パイプ処理されやすいフレームワークです。

JavaScriptにはさまざまなテストフレームワークがあります。この例では、 テープ 。私の意見では、テープはこれらの要件を満たすだけでなく、MochaやJasminなどの他のテストフレームワークよりもクリーンでシンプルです。

テープはに基づいています Test Anything Protocol(TAP) 。

TAPには、ほとんどのプログラミング言語用のバリエーションがあります。

Tapeはテストを入力として受け取り、それらを実行してから、結果をTAPとして出力します。次に、TAPの結果をテストレポーターにパイプするか、raw形式でコンソールに出力することができます。テープはコマンドラインから実行されます。

Tapeには、テストスイート全体を実行する前にロードするモジュールの定義、小さくて単純なアサーションライブラリの提供、テストで呼び出す必要のあるアサーションの数の定義など、いくつかの優れた機能があります。モジュールを使用してプリロードすると、テスト環境の準備が簡単になり、不要なコードを削除できます。

工場図書館

ファクトリライブラリを使用すると、静的フィクスチャファイルを、テスト用のデータを生成するためのはるかに柔軟な方法に置き換えることができます。このようなライブラリを使用すると、面倒で複雑なコードを記述せずに、モデルを定義し、それらのモデルのエンティティを作成できます。

JavaScriptには 工場の女の子 このために-からインスピレーションを得たライブラリ 似たような名前の宝石 、もともとはRuby onRails用に開発されました。

const factory = require('factory-girl').factory; const User = require('../models/user'); factory.define('user', User, { username: 'Bob', number_of_recipes: 50 }); const user = factory.build('user');

開始するには、factory_girlで新しいモデルを定義する必要があります。

名前、プロジェクトのモデル、新しいインスタンスの生成元のオブジェクトで指定されます。

あるいは、新しいインスタンスが生成されるオブジェクトを定義する代わりに、オブジェクトまたはPromiseを返す関数を提供することもできます。

モデルの新しいインスタンスを作成するとき、次のことができます。

  • 新しく生成されたインスタンスの値を上書きします
  • ビルド関数オプションに追加の値を渡します

例を見てみましょう。

const factory = require('factory-girl').factory; const User = require('../models/user'); factory.define('user', User, (buildOptions) => { return ' [email protected] ' }); const user1 = factory.build('user'); // {'name': 'Mike', 'surname': 'Dow', 'email': ' [email protected] '} const user2 = factory.build('user', {name: 'John'}, {email: ' [email protected] '}); // {'name': 'John', 'surname': 'Dow', 'email': ' [email protected] '}

APIへの接続

本格的なHTTPサーバーを起動して実際のHTTPリクエストを作成し、数秒後にそれを破棄するだけで(特に複数のテストを実行する場合)、完全に非効率的であり、統合テストに必要以上に時間がかかる可能性があります。

スーパーテスト は、新しいアクティブサーバーを作成せずにAPIを呼び出すためのJavaScriptライブラリです。これは、TCPリクエストを作成するためのライブラリであるSuperAgentに基づいています。このライブラリを使用すると、新しいTCP接続を作成する必要はありません。 APIはほぼ瞬時に呼び出されます。

約束をサポートするSuperTestは 約束通りのスーパーテスト 。このようなリクエストがpromiseを返すと、ネストされた複数のコールバック関数を回避できるため、フローの処理がはるかに簡単になります。

const express = require('express') const request = require('supertest-as-promised'); const app = express(); request(app).get('/recipes').then(res => assert(....));

SuperTestはExpress.jsフレームワーク用に作成されましたが、わずかな変更を加えるだけで、他のフレームワークでも使用できます。

その他のユーティリティ

場合によっては、コードの依存関係を模倣したり、スパイを使用して関数のロジックをテストしたり、特定の場所でスタブを使用したりする必要があります。ここで、これらのユーティリティパッケージのいくつかが役に立ちます。

SinonJS は、テスト用のスパイ、スタブ、モックをサポートする優れたライブラリです。また、曲げ時間、テストサンドボックス、拡張アサーション、偽のサーバーやリクエストなど、その他の便利なテスト機能もサポートしています。

場合によっては、コードの依存関係をモックする必要があります。モックしたいサービスへの参照は、システムの他の部分で使用されます。

この問題を解決するには、 依存性注入 または、それがオプションでない場合は、Mockeryのようなモックサービスを使用できます。

嘲笑 外部依存関係を持つコードをモックするのに役立ちます。正しく使用するには、テストやコードをロードする前にMockeryを呼び出す必要があります。

const mockery = require('mockery'); mockery.enable({ warnOnReplace: false, warnOnUnregistered: false }); const mockingStripe = require('lib/services/internal/stripe'); mockery.registerMock('lib/services/internal/stripe', mockingStripe);

この新しい参照(この例ではmockingStripe)を使用すると、テストの後半でサービスをモックするのが簡単になります。

const stubStripeTransfer = sinon.stub(mockingStripe, 'transferAmount'); stubStripeTransfer.returns(Promise.resolve(null));

Sinonライブラリの助けを借りて、モックを作成するのは簡単です。ここでの唯一の問題は、このスタブが他のテストに伝播することです。サンドボックス化するには、sinonサンドボックスを使用できます。これを使用すると、後のテストでシステムを初期状態に戻すことができます。

const sandbox = require('sinon').sandbox.create(); const stubStripeTransfer = sandbox.sinon.stub(mockingStripe, 'transferAmount'); stubStripeTransfer.returns(Promise.resolve(null)); // after the test, or better when starting a new test sandbox.restore();

次のような機能のために他のコンポーネントが必要です。

  • データベースを空にする(1つの階層のビルド前クエリで実行できます)
  • 動作状態に設定する( 続編-備品 )
  • サードパーティサービスへのTCP要求のモック( ノック )
  • より豊富なアサーションを使用する( チャイ )
  • サードパーティからの保存された応答( 簡単に修正 )

それほど単純ではないテスト

抽象化と拡張性は、効果的な統合テストスイートを構築するための重要な要素です。テストのコアからフォーカスを取り除くすべて(データの準備、アクション、およびアサーション)は、グループ化してユーティリティ関数に抽象化する必要があります。

Pythonでロボットをプログラムする方法

ここには正しい道も間違った道もありませんが、すべてがプロジェクトとそのニーズに依存するため、いくつかの重要な品質は、優れた統合テストスイートに共通しています。

次のコードは、レシピを作成し、副作用として電子メールを送信するAPIをテストする方法を示しています。

外部の電子メールプロバイダーをスタブ化して、実際に電子メールを送信せずに電子メールが送信されたかどうかをテストできるようにします。このテストでは、APIが適切なステータスコードで応答したかどうかも確認します。

const co = require('co'); const factory = require('factory'); const superTest = require('../utils/super_test'); const basicEnv = require('../utils/basic_test_enivornment'); const path = '/v1/admin/recipes'; basicEnv.test(`API POST ${path}`, co.wrap(function* (t, assert, sandbox) { const chef = yield factory.create(‘chef’); const body = { chef_id: chef.id, recipe_name: ‘cake’, Ingredients: [‘carrot’, ‘chocolate’, ‘biscuit’] }; const stub = sandbox.stub(mockery.emailProvider, 'sendNewEmail').returnsPromise(null); const serverResponse = yield superTest.get(path, body); assert.spies(stub).called(1); assert.statusCode(serverResponse, 201); }));

上記のテストは、毎回クリーンな環境で開始されるため、繰り返し可能です。

セットアップに関連するすべてがbasicEnv.test内に統合されるシンプルなセットアッププロセスがあります。関数。

1つのアクション(単一のAPI)のみをテストします。また、単純なアサートステートメントを通じてテストの期待を明確に示しています。また、テストには、スタブ/モックによるサードパーティのコードは含まれていません。

統合テストの作成を開始します

新しいコードを本番環境にプッシュするとき、開発者(および他のすべてのプロジェクト参加者)は、新しい機能が機能し、古い機能が壊れないことを確認したいと考えています。

これは、テストなしで達成するのは非常に困難であり、不十分に行われると、フラストレーション、プロジェクトの疲労、そして最終的にはプロジェクトの失敗につながる可能性があります。

ユニットテストと組み合わせた統合テストは、防御の最前線です。

2つのうち1つだけを使用するだけでは不十分であり、カバーされていないエラーのために多くのスペースが残ります。常に両方を利用することで、新しいコミットが堅牢になり、すべてのプロジェクト参加者に自信を与え、信頼を得ることができます。

開発用のRaspberryPiサーバーを構築する方法

技術

開発用のRaspberryPiサーバーを構築する方法
アプリ向けの大騒ぎのAI:SalesforceEinsteinに会う

アプリ向けの大騒ぎのAI:SalesforceEinsteinに会う

バックエンド

人気の投稿
Go言語に対する4つの批判
Go言語に対する4つの批判
SVGアニメーションのハウツーガイド
SVGアニメーションのハウツーガイド
説得力のあるデザイン:高度な心理学を効果的に使用する
説得力のあるデザイン:高度な心理学を効果的に使用する
eコマース101:ショッピングカートの放棄を理解する(インフォグラフィック付き)
eコマース101:ショッピングカートの放棄を理解する(インフォグラフィック付き)
開発者向けAndroidM(Android 6.0):正しい方向への進化の一歩
開発者向けAndroidM(Android 6.0):正しい方向への進化の一歩
 
フロントエンドコードのMonoreposガイド
フロントエンドコードのMonoreposガイド
Terraform AWSクラウド:健全なインフラストラクチャ管理
Terraform AWSクラウド:健全なインフラストラクチャ管理
ブロックチェーンテクノロジーの説明:ビットコインへの電力供給
ブロックチェーンテクノロジーの説明:ビットコインへの電力供給
サブスクリプションビジネスモデルに疲れた
サブスクリプションビジネスモデルに疲れた
同じマシンでのMySQLマスタースレーブレプリケーション
同じマシンでのMySQLマスタースレーブレプリケーション
人気の投稿
  • aws認定ソリューションアーキテクトの青写真
  • corp c vs corp s
  • llc s corp c corp
  • データベーステーブルの設計にはどのようなタスクが関係していますか?
  • メディアクエリの書き方
カテゴリー
エンジニアリング管理 その他 トレンド デザイナーライフ 革新 Uiデザイン 製品の担当者とチーム Kpiと分析 Webフロントエンド ヒントとツール

© 2021 | 全著作権所有

apeescape2.com