MountebankとNode.jsを使用してサービスをモックする方法
序章
複雑なサービス指向アーキテクチャー(SOA)では、プログラムが特定のワークフローを実行するために複数のサービスを呼び出す必要があることがよくあります。 すべてが整ったらこれで問題ありませんが、作業中のコードにまだ開発中のサービスが必要な場合は、他のチームが作業を終了するのを待ってから作業を開始することができます。 さらに、テストの目的で、天気APIや記録管理システムなどの外部ベンダーサービスとのやり取りが必要になる場合があります。 ベンダーは通常、必要な数の環境を提供せず、システム上のテストデータを簡単に制御できないことがよくあります。 このような状況では、未完成のサービスや制御できないサービスによって、コードテストがイライラする可能性があります。
これらすべての問題の解決策は、サービスモックを作成することです。 サービスモックは、最終製品で使用するサービスをシミュレートするコードですが、本番環境で使用する実際のサービスよりも軽量で、複雑さが少なく、制御が簡単です。 デフォルトの応答または特定のテストデータを返すようにモックサービスを設定してから、依存するサービスが実際に存在するかのように、テストするソフトウェアを実行できます。 このため、サービスをモックする柔軟な方法を使用すると、ワークフローをより高速かつ効率的にすることができます。
エンタープライズ環境では、模擬サービスの作成はサービス仮想化と呼ばれることもあります。 多くの場合、サービスの仮想化は高価なエンタープライズツールに関連付けられていますが、サービスをモックするために高価なツールは必要ありません。 Mountebank は、RESTやSOAPサービスなどの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をインストールしてローカル開発環境を作成する方法を確認してください。
-
cURLやPostmanなどのHTTPリクエストを作成するためのツール。 ほとんどのマシンにデフォルトでインストールされているため、このチュートリアルではcURLを使用します。 お使いのマシンにcURLがない場合は、インストールドキュメントを参照してください。
ステップ1—Node.jsアプリケーションを起動する
このステップでは、Mountebankインスタンスのベースとして機能する基本的なNode.jsアプリケーションと、後のステップで作成するモックサービスを作成します。
注: Mountebankは、コマンドを使用してグローバルにインストールすることにより、スタンドアロンアプリケーションとして使用できます。 npm install -g mountebank
. その後、で実行できます mb
コマンドを実行し、RESTリクエストを使用してモックを追加します。
これはMountebankを起動して実行するための最速の方法ですが、Mountebankアプリケーションを自分で構築すると、アプリの起動時に事前定義されたモックのセットを実行でき、ソース管理に保存してチームと共有できます。 このチュートリアルでは、これを利用するためにMountebankアプリケーションを手動でビルドします。
まず、アプリケーションを配置するための新しいディレクトリを作成します。 好きな名前を付けることができますが、このチュートリアルでは名前を付けます app
:
- mkdir app
次のコマンドを使用して、新しく作成したディレクトリに移動します。
- cd app
新しいNode.jsアプリケーションを開始するには、次を実行します npm init
プロンプトに記入します。
- npm init
これらのプロンプトからのデータは、 package.json
ファイル。アプリケーションとは何か、アプリケーションが依存するパッケージ、および使用するさまざまなスクリプトが記述されています。 Node.jsアプリケーションでは、スクリプトは、アプリケーションをビルド、実行、およびテストするコマンドを定義します。 プロンプトのデフォルトを使用するか、パッケージ名、バージョン番号などを入力できます。
このコマンドを完了すると、次のような基本的なNode.jsアプリケーションが作成されます。 package.json
ファイル。
次に、以下を使用してMountebanknpmパッケージをインストールします。
- npm install -save mountebank
このコマンドは、Mountebankパッケージを取得し、アプリケーションにインストールします。 必ず使用してください -save
を更新するためのフラグ package.json
Mountebankを依存関係として持つファイル。
次に、開始スクリプトを package.json
コマンドを実行します node src/index.js
. このスクリプトは、アプリのエントリポイントを次のように定義します index.js
、後のステップで作成します。
開く package.json
テキストエディタで。 任意のテキストエディタを使用できますが、このチュートリアルではnanoを使用します。
- nano package.json
に移動します "scripts"
セクションと行を追加します "start": "node src/index.js"
. これにより、 start
アプリケーションを実行するコマンド。
君の 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
ディレクトリ:
- mkdir src
作成したフォルダに移動します。
- cd src
というファイルを作成します settings.js
テキストエディタで開きます。
- nano settings.js
次に、メインのMountebankインスタンスと、後で作成する2つのモックサービスのポートの設定を追加します。
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
テキストエディタで開きます。
- nano index.js
で指定されたポートで実行されるMountebankのインスタンスを開始するには settings.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アドレスに公開しています。
ファイルを保存して終了します。
このファイルを配置したら、次のコマンドを入力してアプリケーションを実行します。
- npm start
コマンドプロンプトが消え、次のように表示されます。
- info: [mb:5000] mountebank v2.0.0 now taking orders - point your browser to http://localhost:5000/ for help
これは、アプリケーションが開いていて、リクエストを受け取る準備ができていることを意味します。
次に、進捗状況を確認します。 新しいターミナルウィンドウを開いて使用する curl
以下を送信するには GET
Mountebankサーバーへのリクエスト:
- 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
図書館:
- npm install -save node-fetch
node-fetch library は、JavaScript Fetch APIの実装を提供します。これを使用して、より短いHTTPリクエストを作成できます。 あなたは標準を使用することができます http
ライブラリ、ただし使用 node-fetch
軽量ソリューションです。
次に、Mountebankにリクエストを送信するクライアントモジュールを作成します。 詐欺師を投稿するだけでよいので、このモジュールには1つの方法があります。
使用する nano
と呼ばれるファイルを作成するには mountebank-helper.js
:
- nano 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
テキストエディタで:
- nano 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
. テキストエディタでファイルを開きます。
- nano index.js
Mountebankインスタンスの作成時に関数が確実に呼び出されるようにするには、次の強調表示された行を追加します。
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の初期化時にモックサービスが作成されることをテストするには、アプリケーションを起動します。
- npm start
Node.jsプロセスがターミナルを占有するため、新しいターミナルウィンドウを開いて、 GET
リクエストする http://localhost:5001/
:
- curl http://localhost:5001
サービスが機能していることを示す次の応答が表示されます。
Output{"message": "hello world"}
アプリケーションをテストしたので、最初のターミナルウィンドウに戻り、次を使用してNode.jsアプリケーションを終了します。 CTRL
+ C
.
このステップでは、最初の模擬サービスを作成しました。 これは、戻るテストサービスのモックです hello world
に応じて GET
リクエスト。 このモックはデモンストレーションを目的としています。 小さなExpressアプリケーションを構築することで得られなかったものは実際には何も得られません。 次のステップでは、Mountebankの機能のいくつかを利用するより複雑なモックを作成します。
ステップ6—データに基づく模擬サービスの構築
前の手順で作成したサービスの種類は一部のシナリオでは問題ありませんが、ほとんどのテストでは、より複雑な一連の応答が必要です。 このステップでは、URLからパラメーターを取得し、それを使用してCSVファイルのレコードを検索するサービスを作成します。
まず、メインに戻ります app
ディレクトリ:
- cd ~/app
というフォルダを作成します data
:
- mkdir data
と呼ばれる顧客データのファイルを開きます customers.csv
:
- nano 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
ディレクトリ:
- nano src/customer-service.js
耳を傾ける詐欺師を作成するには GET
のリクエスト /customers/
エンドポイントに、次のコードを追加します。
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
初期化関数に新しいサービスモックを追加するには:
- nano 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
.
- 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アプリケーションをセットアップする方法を確認してください。