CucumberJS(BDD)によるREST APIテスト
8513 ワード
導入
BDDは非技術的で技術的な人々のための非常に強力なツールです.
この記事では、残りのAPIをテストするために、どのように設定してキュウリを実行する方法を示します.
何が本当にBDDですか?
BDDは行動駆動型開発のための短い
BDDはソフトウェアチームにとって、ビジネスと技術者の間のギャップをクローズする方法です
BDDは行動駆動型開発のための短い
BDDはソフトウェアチームにとって、ビジネスと技術者の間のギャップをクローズする方法です
我々は、具体的な、現実世界の例の周りの共同作業を集中することによってこれを行います.これらの例を使って、コンセプトから実装まで導く.
きゅうりは何ですか。
キュウリは、行動駆動開発(BDD)をサポートするツールです.キュウリは、プレーンテキストで書かれた実行可能な仕様を読み込み、ソフトウェアがこれらの仕様が何を言うかを検証します.仕様は、複数の例、またはシナリオから成ります.例えば、
Scenario Outline: create a contact
Given A contact <request>
When I send POST request to /directory
Then I get response code 201
(このシナリオはgherkin文法で書かれています)
各シナリオは、キュウリの作業のための手順のリストです.キュウリは、ソフトウェアが仕様に準拠していることを検証し、レポートを示す✅ 成功❌ 各シナリオの失敗.
何がgherkinですか?
gherkinは、プレーンテキストを十分にキュウリの理解するために構造化された文法規則のセットです.gherkinドキュメントが格納されます.機能のテキストファイルは、通常、ソースのコントロールでは、ソフトウェアと一緒にバージョン管理されます.
どのようにgherkinのです。あなたのコードに機能ファイル接着剤?
Gerkinの機能ファイルから各ステップのステップ定義を記述します.ステップ定義はGerkinの手順をプログラミングコードに接続します.ステップ定義は、ステップによって実行されるべき動作を実行する.したがって、ステップ定義は、仕様を実装にハードワイヤーします.
機能
特徴は、関連するシナリオのグループです.このように、アプリケーションで多くの関連するテストをテストします.理想的には、gherkinファイルの機能は密接にアプリケーションの機能にマップされます-したがって、名前
それから、シナリオは特定の方法で注文されます.
与えられたこれらのステップは、テストを行う前に初期状態を設定するために使用されます
これらのステップは実行されるべき実際のテストです
それから、これらのステップはテストの結果をアサートするために使用されます
例
私はディレクトリを管理する簡単なREST APIを作成しました.私は連絡先を作成することができます変更、それを読んで、連絡先を削除します.私はBDDテストをすべての機能が設計通りに動作するように書かれている.
セットアッププロジェクト
npm init
依存関係をインストールする
"dependencies": {
"axios": "^0.20.0",
},
"devDependencies": {
"cucumber": "^6.0.5",
"cucumber-html-reporter": "^5.2.0"
}
ディレクトリを作る。src /機能の特徴ファイル
@directory-service
Feature: Directory Service
In order to manage directory
As a developer
I want to make sure CRUD operations through REST API works fine
Scenario Outline: create a contact
Given A contact <request>
When I send POST request to /directory
Then I get response code 201
Examples:
| request
| {"id":99,"name":"Dwayne Klocko","email":"[email protected]","phoneNumber":"1-876-420-9890"} |
| {"id":7,"name":"Ian Weimann DVM","email":"[email protected]","phoneNumber":"(297) 962-1879"} |
Scenario Outline: modify contact
Given The contact with <id> exist
When I send PATCH request with a <secondaryPhoneNumber> to /directory
Then I get response code 200
Examples:
| id | secondaryPhoneNumber |
| 99 | {"secondaryPhoneNumber": "(914) 249-3519"} |
| 7 | {"secondaryPhoneNumber": "788.323.7782"} |
Scenario Outline: get contact
Given The contact with <id> exist
When I send GET request to /directory
Then I receive <response>
Examples:
| id | response |
| 99 | {"id":99,"name":"Dwayne Klocko","email":"[email protected]","phoneNumber":"1-876-420-9890","secondaryPhoneNumber": "(914) 249-3519"} |
| 7 | {"id":7,"name":"Ian Weimann DVM","email":"[email protected]","phoneNumber":"(297) 962-1879", "secondaryPhoneNumber": "788.323.7782"} |
Scenario Outline: delete contact
Given The contact with <id> exist
When I send DELETE request to /directory
Then I get response code 200
Examples:
| id |
| 99 |
| 7 |
ディレクトリを作る。Src /ステップのJS
const {Given, When, Then, AfterAll, After} = require('cucumber');
const assert = require('assert').strict
const restHelper = require('./../util/restHelper');
Given('A contact {}', function (request) {
this.context['request'] = JSON.parse(request);
});
When('I send POST request to {}', async function (path) {
this.context['response'] = await restHelper.postData(`${process.env.SERVICE_URL}${path}`, this.context['request']);
})
Then('I get response code {int}', async function (code) {
assert.equal(this.context['response'].status, code);
});
When('I send PATCH request with a {} to {}', async function (phoneNumberPayload, path) {
const response = await restHelper.patchData(`${process.env.SERVICE_URL}${path}/${this.context['id']}`, JSON.parse(phoneNumberPayload));
this.context['response'] = response;
})
Given('The contact with {int} exist', async function (id) {
this.context['id'] = id;
})
When('I send GET request to {}', async function (path) {
const response = await restHelper.getData(`${process.env.SERVICE_URL}${path}/${this.context['id']}`);
this.context['response'] = response;
})
Then(/^I receive (.*)$/, async function (expectedResponse) {
assert.deepEqual(this.context['response'].data, JSON.parse(expectedResponse));
})
When('I send DELETE request to {}', async function (path) {
const response = await restHelper.deleteData(`${process.env.SERVICE_URL}${path}/${this.context['id']}`);
this.context['response'] = response;
})
実際の残りの呼び出しを行うサービスを作成する
任意のHTTPクライアントを使用することができます、私はAxiosを使用します.
テストを実行し、レポートを生成するには
npm i
"./node_modules/.bin/cucumber-js -f json:cucumber.json src/features/ -r src/steps/ --tags '@directory-service'"
このコマンドでは、並行して3つのシナリオを同時に実行します.
以上です.私は、それがキュウリとgherkinでbddの要点であることを意味します.
ここではサンプルキュウリレポートです.
ステップ間のデータの共有
ほとんどの場合、ステップ間のデータを共有する必要があります.キュウリは、このように、世界として知られているフックと手順にさらされ、各シナリオの孤立したコンテキストを提供します.デフォルトのコンストラクタは以下の通りです:
function World({ attach, log, parameters }) {
this.attach = attach
this.log = log
this.parameters = parameters
}
注意:ステップを使用したい場合は、手順で匿名関数を使用してはいけません.
const {setWorldConstructor} = require("cucumber");
if (!process.env.DIRECTORY_SERVICE_URL) {
require('dotenv-flow').config();
}
class CustomWorld {
constructor({parameters}) {
this.context = {};
}
}
setWorldConstructor(CustomWorld);
以下はこのデモの間に使った便利なライブラリです.
. envファイル
私は環境変数を格納するためにdotenv flow npmを使いました.
参考:https://github.com/kerimdzhanov/dotenv-flow
セットアップモックレストAPI
私はJSONサーバNPMを使用してセットアップモックレストAPIを持っている.
参考:https://github.com/typicode/json-server
キュウリのために
https://github.com/cucumber/cucumber-js
ソースコード-
要約では、BDDはすべてのステークホルダーからのコラボレーションのためのグラウンドを設定します.タグを使用すると、dev、sit、uatのためのBDDのスーツの別のセットを実行することができますもビルドパイプラインをprod.このセットアップは、CI/CDの練習で本当に効果的である可能性があります、それは開発と展開サイクルをスピードアップすることができますが、基本的な品質チェックを適切に維持します.
Scenario Outline: create a contact
Given A contact <request>
When I send POST request to /directory
Then I get response code 201
npm init
"dependencies": {
"axios": "^0.20.0",
},
"devDependencies": {
"cucumber": "^6.0.5",
"cucumber-html-reporter": "^5.2.0"
}
@directory-service
Feature: Directory Service
In order to manage directory
As a developer
I want to make sure CRUD operations through REST API works fine
Scenario Outline: create a contact
Given A contact <request>
When I send POST request to /directory
Then I get response code 201
Examples:
| request
| {"id":99,"name":"Dwayne Klocko","email":"[email protected]","phoneNumber":"1-876-420-9890"} |
| {"id":7,"name":"Ian Weimann DVM","email":"[email protected]","phoneNumber":"(297) 962-1879"} |
Scenario Outline: modify contact
Given The contact with <id> exist
When I send PATCH request with a <secondaryPhoneNumber> to /directory
Then I get response code 200
Examples:
| id | secondaryPhoneNumber |
| 99 | {"secondaryPhoneNumber": "(914) 249-3519"} |
| 7 | {"secondaryPhoneNumber": "788.323.7782"} |
Scenario Outline: get contact
Given The contact with <id> exist
When I send GET request to /directory
Then I receive <response>
Examples:
| id | response |
| 99 | {"id":99,"name":"Dwayne Klocko","email":"[email protected]","phoneNumber":"1-876-420-9890","secondaryPhoneNumber": "(914) 249-3519"} |
| 7 | {"id":7,"name":"Ian Weimann DVM","email":"[email protected]","phoneNumber":"(297) 962-1879", "secondaryPhoneNumber": "788.323.7782"} |
Scenario Outline: delete contact
Given The contact with <id> exist
When I send DELETE request to /directory
Then I get response code 200
Examples:
| id |
| 99 |
| 7 |
const {Given, When, Then, AfterAll, After} = require('cucumber');
const assert = require('assert').strict
const restHelper = require('./../util/restHelper');
Given('A contact {}', function (request) {
this.context['request'] = JSON.parse(request);
});
When('I send POST request to {}', async function (path) {
this.context['response'] = await restHelper.postData(`${process.env.SERVICE_URL}${path}`, this.context['request']);
})
Then('I get response code {int}', async function (code) {
assert.equal(this.context['response'].status, code);
});
When('I send PATCH request with a {} to {}', async function (phoneNumberPayload, path) {
const response = await restHelper.patchData(`${process.env.SERVICE_URL}${path}/${this.context['id']}`, JSON.parse(phoneNumberPayload));
this.context['response'] = response;
})
Given('The contact with {int} exist', async function (id) {
this.context['id'] = id;
})
When('I send GET request to {}', async function (path) {
const response = await restHelper.getData(`${process.env.SERVICE_URL}${path}/${this.context['id']}`);
this.context['response'] = response;
})
Then(/^I receive (.*)$/, async function (expectedResponse) {
assert.deepEqual(this.context['response'].data, JSON.parse(expectedResponse));
})
When('I send DELETE request to {}', async function (path) {
const response = await restHelper.deleteData(`${process.env.SERVICE_URL}${path}/${this.context['id']}`);
this.context['response'] = response;
})
npm i
"./node_modules/.bin/cucumber-js -f json:cucumber.json src/features/ -r src/steps/ --tags '@directory-service'"
function World({ attach, log, parameters }) {
this.attach = attach
this.log = log
this.parameters = parameters
}
const {setWorldConstructor} = require("cucumber");
if (!process.env.DIRECTORY_SERVICE_URL) {
require('dotenv-flow').config();
}
class CustomWorld {
constructor({parameters}) {
this.context = {};
}
}
setWorldConstructor(CustomWorld);
私は環境変数を格納するためにdotenv flow npmを使いました.
参考:https://github.com/kerimdzhanov/dotenv-flow
セットアップモックレストAPI
私はJSONサーバNPMを使用してセットアップモックレストAPIを持っている.
参考:https://github.com/typicode/json-server
キュウリのために
https://github.com/cucumber/cucumber-js
ソースコード-
要約では、BDDはすべてのステークホルダーからのコラボレーションのためのグラウンドを設定します.タグを使用すると、dev、sit、uatのためのBDDのスーツの別のセットを実行することができますもビルドパイプラインをprod.このセットアップは、CI/CDの練習で本当に効果的である可能性があります、それは開発と展開サイクルをスピードアップすることができますが、基本的な品質チェックを適切に維持します.
Reference
この問題について(CucumberJS(BDD)によるREST APIテスト), 我々は、より多くの情報をここで見つけました https://dev.to/ynmanware/bdd-for-rest-api-using-cucumber-js-2polテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol