序章

複雑なサービス指向アーキテクチャー(SOA)では、プログラムが特定のワークフローを実行するために複数のサービスを呼び出す必要があることがよくあります。 すべてが整ったらこれで問題ありませんが、作業中のコードにまだ開発中のサービスが必要な場合は、他のチームが作業を終了するのを待ってから作業を開始することができます。 さらに、テストの目的で、天気APIや記録管理システムなどの外部ベンダーサービスとのやり取りが必要になる場合があります。 ベンダーは通常、必要な数の環境を提供せず、システム上のテストデータを簡単に制御できないことがよくあります。 このような状況では、未完成のサービスや制御できないサービスによって、コードテストがイライラする可能性があります。

これらすべての問題の解決策は、サービスモックを作成することです。 サービスモックは、最終製品で使用するサービスをシミュレートするコードですが、本番環境で使用する実際のサービスよりも軽量で、複雑さが少なく、制御が簡単です。 デフォルトの応答または特定のテストデータを返すようにモックサービスを設定してから、依存するサービスが実際に存在するかのように、テストするソフトウェアを実行できます。 このため、サービスをモックする柔軟な方法を使用すると、ワークフローをより高速かつ効率的にすることができます。

エンタープライズ環境では、模擬サービスの作成はサービス仮想化と呼ばれることもあります。 多くの場合、サービスの仮想化は高価なエンタープライズツールに関連付けられていますが、サービスをモックするために高価なツールは必要ありません。 Mountebank は、RESTSOAPサービスなどのHTTPサービスをモックするために使用できる無料のオープンソースサービスモックツールです。 また、SMTPまたはTCPリクエストをモックするために使用することもできます。

このガイドでは、 Node.js とMountebankを使用して、2つの柔軟なサービスモッキングアプリケーションを構築します。 両方のモックサービスは、HTTPでのRESTリクエストの特定のポートをリッスンします。 この単純なモック動作に加えて、サービスはカンマ区切り値(CSV)ファイルからモックデータも取得します。 このチュートリアルを終えると、あらゆる種類のサービスの動作を模倣できるようになるため、アプリケーションをより簡単に開発およびテストできます。

前提条件

このチュートリアルに従うには、次のものが必要です。

  • マシンにインストールされているNode.jsのバージョン8.10.0以降。 このチュートリアルでは、バージョン8.10.0を使用します。 Node.jsをインストールするには、 Ubuntu18.04にNode.jsをインストールする方法またはmacOSにNode.jsをインストールしてローカル開発環境を作成する方法を確認してください。

  • cURLPostmanなどのHTTPリクエストを作成するためのツール。 ほとんどのマシンにデフォルトでインストールされているため、このチュートリアルではcURLを使用します。 お使いのマシンにcURLがない場合は、インストールドキュメントを参照してください。

ステップ1—Node.jsアプリケーションを起動する

このステップでは、Mountebankインスタンスのベースとして機能する基本的なNode.jsアプリケーションと、後のステップで作成するモックサービスを作成します。

注: Mountebankは、コマンドを使用してグローバルにインストールすることにより、スタンドアロンアプリケーションとして使用できます。 npm install -g mountebank. その後、で実行できます mb コマンドを実行し、RESTリクエストを使用してモックを追加します。

これはMountebankを起動して実行するための最速の方法ですが、Mountebankアプリケーションを自分で構築すると、アプリの起動時に事前定義されたモックのセットを実行でき、ソース管理に保存してチームと共有できます。 このチュートリアルでは、これを利用するためにMountebankアプリケーションを手動でビルドします。

まず、アプリケーションを配置するための新しいディレクトリを作成します。 好きな名前を付けることができますが、このチュートリアルでは名前を付けます app:

  1. mkdir app

次のコマンドを使用して、新しく作成したディレクトリに移動します。

  1. cd app

新しいNode.jsアプリケーションを開始するには、次を実行します npm init プロンプトに記入します。

  1. npm init

これらのプロンプトからのデータは、 package.json ファイル。アプリケーションとは何か、アプリケーションが依存するパッケージ、および使用するさまざまなスクリプトが記述されています。 Node.jsアプリケーションでは、スクリプトは、アプリケーションをビルド、実行、およびテストするコマンドを定義します。 プロンプトのデフォルトを使用するか、パッケージ名、バージョン番号などを入力できます。

このコマンドを完了すると、次のような基本的なNode.jsアプリケーションが作成されます。 package.json ファイル。

次に、以下を使用してMountebanknpmパッケージをインストールします。

  1. npm install -save mountebank

このコマンドは、Mountebankパッケージを取得し、アプリケーションにインストールします。 必ず使用してください -save を更新するためのフラグ package.json Mountebankを依存関係として持つファイル。

次に、開始スクリプトを package.json コマンドを実行します node src/index.js. このスクリプトは、アプリのエントリポイントを次のように定義します index.js、後のステップで作成します。

開く package.json テキストエディタで。 任意のテキストエディタを使用できますが、このチュートリアルではnanoを使用します。

  1. nano package.json

に移動します "scripts" セクションと行を追加します "start": "node src/index.js". これにより、 start アプリケーションを実行するコマンド。

君の package.json 最初のプロンプトの入力方法に応じて、ファイルは次のようになります。

app / package.json
{
  "name": "diy-service-virtualization",
  "version": "1.0.0",
  "description": "An application to mock services.",
  "main": "index.js",
  "scripts": {
    "start": "node src/index.js"
  },
  "author": "Dustin Ewers",
  "license": "MIT",
  "dependencies": {
    "mountebank": "^2.0.0"
  }
}

これで、アプリを作成し、Mountebankをインストールし、開始スクリプトを追加して構築したMountebankアプリケーションのベースができました。 次に、アプリケーション固有の設定を保存するための設定ファイルを追加します。

ステップ2—設定ファイルを作成する

このステップでは、Mountebankインスタンスと2つのモックサービスがリッスンするポートを決定する設定ファイルを作成します。

Mountebankまたはモックサービスのインスタンスを実行するたびに、そのサービスが実行されるネットワークポートを指定する必要があります(例: http://localhost:5000/). これらを設定ファイルに入れることで、アプリケーションの他の部分は、サービスとMountebankインスタンスのポート番号を知る必要があるときはいつでもこれらの設定をインポートできるようになります。 これらを定数としてアプリケーションに直接コーディングすることもできますが、ファイルに保存すると、後で設定を変更するのが簡単になります。 このように、1か所で値を変更するだけで済みます。

と呼ばれるディレクトリを作成することから始めます src あなたから app ディレクトリ:

  1. mkdir src

作成したフォルダに移動します。

  1. cd src

というファイルを作成します settings.js テキストエディタで開きます。

  1. nano settings.js

次に、メインのMountebankインスタンスと、後で作成する2つのモックサービスのポートの設定を追加します。

app / src / settings.js
module.exports = {
    port: 5000,
    hello_service_port: 5001,
    customer_service_port: 5002
}

この設定ファイルには、次の3つのエントリがあります。 port: 5000 ポートを割り当てます 5000 メインのMountebankインスタンスに、 hello_service_port: 5001 ポートを割り当てます 5001 後のステップで作成するHelloWorldテストサービスに移動し、 customer_service_port: 5002 ポートを割り当てます 5002 CSVデータで応答する模擬サービスアプリに。 ここのポートが占有されている場合は、自由に変更してください。 module.exports = 他のファイルがこれらの設定をインポートできるようにします。

このステップでは、 settings.js Mountebankとモックサービスがリッスンするポートを定義し、これらの設定をアプリの他の部分で利用できるようにします。 次のステップでは、これらの設定を使用して初期化スクリプトを作成し、Mountebankを起動します。

ステップ3—初期化スクリプトの作成

このステップでは、Mountebankのインスタンスを開始するファイルを作成します。 このファイルはアプリケーションのエントリポイントになります。つまり、アプリを実行すると、このスクリプトが最初に実行されます。 新しいサービスモックを作成するときに、このファイルにさらに行を追加します。

から src ディレクトリ、というファイルを作成します index.js テキストエディタで開きます。

  1. nano index.js

で指定されたポートで実行されるMountebankのインスタンスを開始するには settings.js 前の手順で作成したファイルに、次のコードをファイルに追加します。

app / src / index.js
const mb = require('mountebank');
const settings = require('./settings');

const mbServerInstance = mb.create({
        port: settings.port,
        pidfile: '../mb.pid',
        logfile: '../mb.log',
        protofile: '../protofile.json',
        ipWhitelist: ['*']
    });

このコードは3つのことを行います。 まず、以前にインストールしたMountebank npmパッケージをインポートします(const mb = require('mountebank');). 次に、前の手順で作成した設定モジュールをインポートします(const settings = require('./settings');). 最後に、Mountebankサーバーのインスタンスを作成します。 mb.create().

サーバーは、設定ファイルで指定されたポートでリッスンします。 The pidfile, logfile、 と protofile パラメータは、Mountebankが内部でプロセスIDを記録し、ログを保持する場所を指定し、カスタムプロトコル実装をロードするようにファイルを設定するために使用するファイル用です。 The ipWhitelist 設定は、Mountebankサーバーとの通信を許可するIPアドレスを指定します。 この場合、任意のIPアドレスに公開しています。

ファイルを保存して終了します。

このファイルを配置したら、次のコマンドを入力してアプリケーションを実行します。

  1. npm start

コマンドプロンプトが消え、次のように表示されます。

  1. info: [mb:5000] mountebank v2.0.0 now taking orders - point your browser to http://localhost:5000/ for help

これは、アプリケーションが開いていて、リクエストを受け取る準備ができていることを意味します。

次に、進捗状況を確認します。 新しいターミナルウィンドウを開いて使用する curl 以下を送信するには GET Mountebankサーバーへのリクエスト:

  1. curl http://localhost:5000/

これにより、次のJSON応答が返されます。

Output
{ "_links": { "imposters": { "href": "http://localhost:5000/imposters" }, "config": { "href": "http://localhost:5000/config" }, "logs": { "href": "http://localhost:5000/logs" } } }

Mountebankが返すJSONは、Mountebankでオブジェクトを追加または削除するために使用できる3つの異なるエンドポイントを記述しています。 を使用して curl これらのエンドポイントにリクエストを送信するには、Mountebankインスタンスを操作できます。

完了したら、最初のターミナルウィンドウに戻り、を使用してアプリケーションを終了します。 CTRL + C. これでNode.jsアプリが終了するため、引き続き追加できます。

これで、Mountebankのインスタンスを正常に実行するアプリケーションができました。 次のステップでは、RESTリクエストを使用してMountebankアプリケーションにモックサービスを追加するMountebankクライアントを作成します。

ステップ4—Mountebankクライアントの構築

Mountebankは、RESTAPIを使用して通信します。 前の手順で説明したさまざまなエンドポイントにHTTPリクエストを送信することで、Mountebankインスタンスのリソースを管理できます。 模擬サービスを追加するには、HTTPを送信します POST 詐欺師のエンドポイントへのリクエスト。 imposter は、Mountebankの模擬サービスの名前です。 詐欺師は、モックで必要な動作に応じて、単純なものから複雑なものまであります。

このステップでは、Mountebankクライアントを構築して自動的に送信します POST Mountebankサービスへのリクエスト。 あなたは送ることができます POST を使用して詐欺師エンドポイントへのリクエスト curl またはPostmanですが、テストサーバーを再起動するたびに同じリクエストを送信する必要があります。 複数のモックを使用してサンプルAPIを実行している場合は、これを行うためのクライアントスクリプトを作成する方が効率的です。

インストールすることから始めます node-fetch 図書館:

  1. npm install -save node-fetch

node-fetch library は、JavaScript Fetch APIの実装を提供します。これを使用して、より短いHTTPリクエストを作成できます。 あなたは標準を使用することができます http ライブラリ、ただし使用 node-fetch 軽量ソリューションです。

次に、Mountebankにリクエストを送信するクライアントモジュールを作成します。 詐欺師を投稿するだけでよいので、このモジュールには1つの方法があります。

使用する nano と呼ばれるファイルを作成するには mountebank-helper.js:

  1. nano mountebank-helper.js

クライアントを設定するには、ファイルに次のコードを入力します。

app / src / mountebank-helper.js
const fetch = require('node-fetch');
const settings = require('./settings');

function postImposter(body) {
    const url = `http://127.0.0.1:${settings.port}/imposters`;

    return fetch(url, {
                    method:'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify(body)
                });
}

module.exports = { postImposter };

このコードは、 node-fetch ライブラリと設定ファイル。 次に、このモジュールは、と呼ばれる関数を公開します postImposter Mountebankにサービスモックを投稿します。 次、 body: 関数が取ると決定します JSON.stringify(body)、JavaScriptオブジェクト。 このオブジェクトはあなたがしようとしているものです POST Mountebankサービスへ。 このメソッドはローカルで実行されているため、 127.0.0.1 (localhost). fetchメソッドは、パラメーターで送信されたオブジェクトを受け取り、 POST にリクエスト url.

このステップでは、Mountebankサーバーに新しいモックサービスを投稿するMountebankクライアントを作成しました。 次のステップでは、このクライアントを使用して最初の模擬サービスを作成します。

ステップ5—最初の模擬サービスを作成する

前の手順では、Mountebankサーバーとそのサーバーを呼び出すコードを作成するアプリケーションを作成しました。 次に、そのコードを使用して、詐欺師または模擬サービスを構築します。

Mountebankでは、各詐欺師にはスタブが含まれています。 スタブは、詐欺師が与える応答を決定する構成セットです。 スタブは、述語と応答の組み合わせにさらに分割できます。 述語は、詐欺師の応答をトリガーするルールです。 述語は、URL、リクエストコンテンツ(XMLまたはJSONを使用)、HTTPメソッドなど、さまざまな種類の情報を使用できます。

Model-View-Controller(MVC)アプリの観点から見ると、詐欺師はコントローラーのように機能し、スタブはそのコントローラー内のアクションのように機能します。 述語は、特定のコントローラーアクションを指すルーティングルールです。

最初のモックサービスを作成するには、というファイルを作成します hello-service.js. このファイルには、モックサービスの定義が含まれています。

開ける hello-service.js テキストエディタで:

  1. nano hello-service.js

次に、次のコードを追加します。

app / src / hello-service.js
const mbHelper = require('./mountebank-helper');
const settings = require('./settings');

function addService() {
    const response = { message: "hello world" }

    const stubs = [
        {
            predicates: [ {
                equals: {
                    method: "GET",
                    "path": "/"
                }
            }],
            responses: [
                {
                    is: {
                        statusCode: 200,
                        headers: {
                            "Content-Type": "application/json"
                        },
                        body: JSON.stringify(response)
                    }
                }
            ]
        }
    ];

    const imposter = {
        port: settings.hello_service_port,
        protocol: 'http',
        stubs: stubs
    };

    return mbHelper.postImposter(imposter);
}

module.exports = { addService };

このコードは、述語と応答を含む単一のスタブを持つ詐欺師を定義します。 次に、そのオブジェクトをMountebankサーバーに送信します。 このコードは、リッスンする新しいモックサービスを追加します GET ルートへのリクエスト url と戻ります { message: "hello world" } それが1つを取得したとき。

見てみましょう addService() 上記のコードが作成する関数。 まず、応答メッセージを定義します hello world:

    const response = { message: "hello world" }
...

次に、スタブを定義します。

...
        const stubs = [
        {
            predicates: [ {
                equals: {
                    method: "GET",
                    "path": "/"
                }
            }],
            responses: [
                {
                    is: {
                        statusCode: 200,
                        headers: {
                            "Content-Type": "application/json"
                        },
                        body: JSON.stringify(response)
                    }
                }
            ]
        }
    ];
...

このスタブには2つの部分があります。 述語部分はを探しています GET ルートへのリクエスト(/)URL。 この意味は stubs 誰かが送信したときに応答を返します GET モックサービスのルートURLへのリクエスト。 スタブの2番目の部分は responses 配列。 この場合、1つの応答があり、HTTPステータスコードが次のJSON結果を返します。 200.

最後のステップでは、そのスタブを含む詐欺師を定義します。

...
    const imposter = {
        port: settings.hello_service_port,
        protocol: 'http',
        stubs: stubs
    };
...

これは、送信するオブジェクトです。 /imposters エンドポイントは、単一のエンドポイントでサービスを模倣する詐欺師を作成します。 上記のコードは、 port 設定ファイルで決定したポートに、 protocol HTTPに割り当て、 stubs 詐欺師のスタブとして。

これで模擬サービスができたので、コードはそれをMountebankサーバーに送信します。

...
    return mbHelper.postImposter(imposter);
...

前述のように、MountebankはRESTAPIを使用してオブジェクトを管理します。 上記のコードは postImposter() 送信するために以前に定義した関数 POST サーバーにサービスをアクティブ化するように要求します。

終了したら hello-service.js、保存してファイルを終了します。

次に、新しく作成したものを呼び出します addService() で機能する index.js. テキストエディタでファイルを開きます。

  1. nano index.js

Mountebankインスタンスの作成時に関数が確実に呼び出されるようにするには、次の強調表示された行を追加します。

app / src / index.js
const mb = require('mountebank');
const settings = require('./settings');
const helloService = require('./hello-service');

const mbServerInstance = mb.create({
        port: settings.port,
        pidfile: '../mb.pid',
        logfile: '../mb.log',
        protofile: '../protofile.json',
        ipWhitelist: ['*']
    });

mbServerInstance.then(function() {
    helloService.addService();
});

Mountebankインスタンスが作成されると、promiseが返されます。 約束は、後でまでその値を決定しないオブジェクトです。 これは、非同期関数呼び出しを単純化するために使用できます。 上記のコードでは、 .then(function(){...}) 関数は、Mountebankサーバーが初期化されたときに実行されます。これは、promiseが解決されたときに発生します。

保存して終了 index.js.

Mountebankの初期化時にモックサービスが作成されることをテストするには、アプリケーションを起動します。

  1. npm start

Node.jsプロセスがターミナルを占有するため、新しいターミナルウィンドウを開いて、 GET リクエストする http://localhost:5001/:

  1. curl http://localhost:5001

サービスが機能していることを示す次の応答が表示されます。

Output
{"message": "hello world"}

アプリケーションをテストしたので、最初のターミナルウィンドウに戻り、次を使用してNode.jsアプリケーションを終了します。 CTRL + C.

このステップでは、最初の模擬サービスを作成しました。 これは、戻るテストサービスのモックです hello world に応じて GET リクエスト。 このモックはデモンストレーションを目的としています。 小さなExpressアプリケーションを構築することで得られなかったものは実際には何も得られません。 次のステップでは、Mountebankの機能のいくつかを利用するより複雑なモックを作成します。

ステップ6—データに基づく模擬サービスの構築

前の手順で作成したサービスの種類は一部のシナリオでは問題ありませんが、ほとんどのテストでは、より複雑な一連の応答が必要です。 このステップでは、URLからパラメーターを取得し、それを使用してCSVファイルのレコードを検索するサービスを作成します。

まず、メインに戻ります app ディレクトリ:

  1. cd ~/app

というフォルダを作成します data:

  1. mkdir data

と呼ばれる顧客データのファイルを開きます customers.csv:

  1. nano data/customers.csv

次のテストデータを追加して、モックサービスが取得できるものを用意します。

app / data / Customers.csv
id,first_name,last_name,email,favorite_color 
1,Erda,Birkin,[email protected],Aquamarine
2,Cherey,Endacott,[email protected],Fuscia
3,Shalom,Westoff,[email protected],Red
4,Jo,Goulborne,[email protected],Red

これは、APIモッキングツール Mockaroo によって生成された偽の顧客データであり、サービス自体の顧客テーブルにロードする偽のデータに似ています。

ファイルを保存して終了します。

次に、という新しいモジュールを作成します customer-service.js の中に src ディレクトリ:

  1. nano src/customer-service.js

耳を傾ける詐欺師を作成するには GET のリクエスト /customers/ エンドポイントに、次のコードを追加します。

app / src / customer-service.js
const mbHelper = require('./mountebank-helper');
const settings = require('./settings');

function addService() {
    const stubs = [
        {
            predicates: [{
                and: [
                    { equals: { method: "GET" } },
                    { startsWith: { "path": "/customers/" } }
                ]
            }],
            responses: [
                {
                    is: {
                        statusCode: 200,
                        headers: {
                            "Content-Type": "application/json"
                        },
                        body: '{ "firstName": "${row}[first_name]", "lastName": "${row}[last_name]", "favColor": "${row}[favorite_color]" }'
                    },
                    _behaviors: {
                        lookup: [
                            {
                                "key": {
                                  "from": "path",
                                  "using": { "method": "regex", "selector": "/customers/(.*)$" },
                                  "index": 1
                                },
                                "fromDataSource": {
                                  "csv": {
                                    "path": "data/customers.csv",
                                    "keyColumn": "id"
                                  }
                                },
                                "into": "${row}"
                              }
                        ]
                    }
                }
            ]
        }
    ];

    const imposter = {
        port: settings.customer_service_port,
        protocol: 'http',
        stubs: stubs
    };

    return mbHelper.postImposter(imposter);
}

module.exports = { addService };

このコードは、検索するサービスモックを定義します GET URL形式が次のリクエスト customers/<id>. リクエストを受信すると、URLにクエリを実行します。 id 次に、CSVファイルから対応するレコードを返します。

このコードは、Mountebankの機能よりもいくつか多くの機能を使用しています。 hello 最後のステップで作成したサービス。 まず、の動作と呼ばれるMountebankの機能を使用します。 ビヘイビアーは、スタブに機能を追加する方法です。 この場合、使用しているのは lookup CSVファイルのレコードを検索する動作:

...
  _behaviors: {
      lookup: [
          {
              "key": {
                "from": "path",
                "using": { "method": "regex", "selector": "/customers/(.*)$" },
                "index": 1
              },
              "fromDataSource": {
                "csv": {
                  "path": "data/customers.csv",
                  "keyColumn": "id"
                }
              },
              "into": "${row}"
            }
      ]
  }
...

The key プロパティは、正規表現を使用して着信パスを解析します。 この場合、あなたは id それは後に来る customers/ URLで。

The fromDataSource プロパティは、テストデータの保存に使用しているファイルを指します。

The into プロパティは結果を変数に挿入します ${row}. その変数は以下で参照されます body セクション:

...
  is: {
      statusCode: 200,
      headers: {
          "Content-Type": "application/json"
      },
      body: '{ "firstName": "${row}[first_name]", "lastName": "${row}[last_name]", "favColor": "${row}[favorite_color]" }'
  },
...

行変数は、応答の本文に入力するために使用されます。 この場合、それは顧客データを含むJSON文字列です。

ファイルを保存して終了します。

次に、開く index.js 初期化関数に新しいサービスモックを追加するには:

  1. nano src/index.js

強調表示された行を追加します。

app / src / index.js
const mb = require('mountebank');
const settings = require('./settings');
const helloService = require('./hello-service');
const customerService = require('./customer-service');

const mbServerInstance = mb.create({
        port: settings.port,
        pidfile: '../mb.pid',
        logfile: '../mb.log',
        protofile: '../protofile.json',
        ipWhitelist: ['*']
    });

mbServerInstance.then(function() {
    helloService.addService();
    customerService.addService();
});

ファイルを保存して終了します。

今Mountebankを開始します npm start. これによりプロンプトが非表示になるため、別のターミナルウィンドウを開きます。 を送信してサービスをテストします GET リクエストする localhost:5002/customers/3. これにより、下の顧客情報が検索されます id 3.

  1. curl localhost:5002/customers/3

次の応答が表示されます。

Output
{ "firstName": "Shalom", "lastName": "Westoff", "favColor": "Red" }

このステップでは、CSVファイルからデータを読み取り、それをJSON応答として返すモックサービスを作成しました。 ここから、テストする必要のあるサービスに一致する、より複雑なモックを作成し続けることができます。

結論

この記事では、MountebankとNode.jsを使用して独自のサービスモッキングアプリケーションを作成しました。 これで、模擬サービスを構築してチームと共有できます。 テストする必要のあるベンダーサービスを含む複雑なシナリオでも、別のチームが作業を終了するのを待つ間の単純なモックでも、モックサービスを作成することでチームを動かし続けることができます。

Mountebankについて詳しく知りたい場合は、Mountebankのドキュメントを確認してください。 このアプリケーションをコンテナ化する場合は、DockerComposeを使用した開発用のNode.jsアプリケーションのコンテナ化を確認してください。 このアプリケーションを本番環境のような環境で実行したい場合は、 Ubuntu18.04で本番用にNode.jsアプリケーションをセットアップする方法を確認してください。