概要

APIテストは、アプリケーションのAPI層をテストするソフトウェアテストの一種です。

APIテストでは、クライアントアプリケーションとサーバー間のリクエストとレスポンスをテストします。これは通常、HTTPリクエストをAPIエンドポイントに送信し、返されたレスポンスを検証することで行われます。APIテストの主な目的は、APIが期待どおりに動作し、さまざまな入力シナリオに対して正しいデータとエラーを返すことを保証することです。

全体として、APIテストは、アプリケーションのAPI層の信頼性と機能を保証するソフトウェアテストの重要な側面であり、開発者が堅牢でスケーラブルなソフトウェアアプリケーションを構築できるようにします。

どのように機能するのですか?

APIテストを実行するには、公式の@nightwatch/apitestingプラグインをインストールする必要があります。このプラグインは以下の機能を提供します。

  1. HTTPリクエストをテストするためのsupertestとの統合
  2. expressに基づく組み込みのモックサーバー。モックされたHTTPリクエストに対するsinonアサーションのサポート

Nightwatch 2.6.4以上が必要です。

インストール

1)NPMからプラグインをインストールします

npm i @nightwatch/apitesting --save-dev

2)リストにプラグインを追加します

Nightwatch設定を更新して、リストにプラグインを追加します

nightwatch.conf.js
module.exports = {
  plugins: ['@nightwatch/apitesting']
  
// other Nightwatch settings... }

3)ブラウザセッションを無効にします

また、APIテストのみを行うため、ブラウザセッションをオフにする必要があります。これは、以下に示すようにnightwatch.conf.jsにAPIテスト用の新しい環境を追加することで実現できます。

nightwatch.conf.js
module.exports = {
  // ....
  api_testing: {
    start_session: false,
    webdriver: {
      start_process: false,
    }
  }
}

設定

プラグインには、現在のところ、コンソールにHTTPレスポンスをログに記録するかどうかという1つの構成オプションしかありません。これは、nightwatch.json(またはnightwatch.conf.js)構成ファイルで構成できます。

nightwatch.conf.js
{
  "@nightwatch/apitesting" : {
    "log_responses": true
  }
}

APIヘッダーとレスポンスのテスト

Nightwatchは内部でsupertestを使用しているため、さまざまなタイプのREST APIヘッダーとレスポンスをテストできます。

GETリクエスト

get-api-test.js
describe('api testing', function () {
  it('get api test', async function({supertest}) {
    await supertest
      .request("https://petstore.swagger.io/v2")
      .get("/pet/findByStatus?status=available")
      .expect(200)
      .expect('Content-Type', /json/)
      .then(function(response){
          expect(response._body.length).to.be.greaterThan(0);
      });
  });
});

POSTリクエスト

post-api-test.js
describe('api testing', function () {
  it('post api test', async function({supertest}) {
    await supertest
      .request("https://petstore.swagger.io/v2")
      .post("/pet")
      .send({
        "id": 0,
        "category": {
          "id": 0,
          "name": "string"
        },
        "name": "doggie",
        "photoUrls": [
          "string"
        ],
        "tags": [
          {
            "id": 0,
            "name": "string"
          }
        ],
        "status": "available"
      })
      .expect(200)
      .expect('Content-Type', /json/)
      .then(function(response){
          expect(response._body.name).to.be.equal("doggie");
      });
  });
});

APIテストの実行

APIテストが、start_sessionwebdriver -> start_processfalseに設定されているenvironmentに対して実行されていることを確認してください。

npx nightwatch <path to tests> --env api_testing

HTMLレポート

テストが実行されると、結果はHTMLレポートで確認できます。

HTML report

統合モックサーバー

@nightwatch/apitestingプラグインは、expressに基づく組み込みのモックサーバーも提供しており、受信HTTPリクエストをアサートするために使用できます。

モックサーバーのサンプルを次に示します

mock-server.js
describe('api testing with supertest in nightwatch POST', function () {
  
let server;
before(async function(client) { server = await client.mockserver.create(); server.setup((app) => { app.post('/api/v1/datasets/', function (req, res) { res.status(200).json({ id: 'test-dataset-id' }); }); });
await server.start(3000); });
after(() => { server.close(); });
it('demo test', async function(client) { const req = await server.request() .post('/api/v1/datasets/') .send({name: 'medea'}) .set('Accept', 'application/json') .expect(200) .expect('Content-Type', /json/);
await client.assert.deepStrictEqual(server.route.post('/api/v1/datasets/').requestBody, {name: 'medea'}); });
});

モックサーバーAPI

  • const mockServer = await client.mockserver.create() – 新しいモックサーバーインスタンスを作成します
  • await mockServer.setup(definition) – 提供されたルート定義で既存のモックサーバーインスタンスを設定します 例
    await mockServer.setup((app) => {
        app.get('/api/v1/schemas', function (req, res) {
          console.log('GET /api/v1/schemas called');
          
    res.status(200).json([ { id: 'test-schema-id1' }, { id: 'test-schema-id2' } ]); }) });
  • await mockServer.start(port) – 指定されたポートで既存のモックサーバーインスタンスを開始します
  • await mockServer.route(path) – 指定されたルート上のsinonスパイを返します

受信リクエストのアサート

mockServer.route(path)メソッドを使用して、指定されたルートのスパイを取得します。次に、sinonアサーションを使用して、受信リクエストをアサートできます。

前のモックサーバーのセットアップ例を考えてみましょう。GET /api/v1/schemasルートが呼び出されたことをアサートしたい場合は、次のように実行できます

it('demo test', async function(client) {
    client
      .assert.strictEqual(mockServer.route.get('/api/v1/schemas').calledOnce, true, 'called once')
      .assert.strictEqual(mockServer.route.get('/api/v1/schemas').calledTwice, false);
  });

リクエストヘッダーのアサート

また、たとえば、chaiを使用する組み込みのexpect()アサーションAPIを使用して、リクエストヘッダーをアサートすることもできます

it('demo test', async function(client) {
    const {requestHeaders} = mockServer.route.get('/api/v1/schemas');
    
client.expect(requestHeaders).to.have.property('connection', 'close'); });

受信POSTデータのアサート

また、受信POSTデータをアサートすることもできます

  1. まず、モックサーバーのPOSTルートを設定します
await mockServer.setup((app) => {
  app.post('/api/v1/datasets/', function (req, res) {
    res.status(200).json({
      id: 'test-dataset-id'
    });
  });
});
  1. 次に、mockServer.route.post(path)メソッドを使用して、指定されたルートのスパイを取得します。次に、sinonアサーションを使用して、受信リクエストをアサートできます。
it('demo test', async function(client) {
    const {requestBody} = mockServer.route.post('/api/v1/schemas');
    
await client.assert.deepStrictEqual(requestBody, {name: 'medea'}); });

受信リクエストテストを待機するには、waitUntil()コマンドを使用できます。

waitUntilを使用した例

it('demo test', async function(client) {
    const timeoutMs = 15000;
    const retryIntervalMs = 500;
    
await client.waitUntil(async function () { const spy = server.route.get('/api/v1/schemas');
if (spy) { return spy.calledOnce; }
return false; }, timeoutMs, retryIntervalMs, new Error(`time out reached (10000ms) while waiting for API call.`));
});