1 つのツールであらゆる要素をテストしたいと思った事はありますか? 開発者なら一度はそう願ったことがあるかもしれません。実は、JavaScript フロントエンド テスト フレームワークである Cypress を使えば、ほぼほぼ叶えられるのです。 Cypress は JavaScript フロントエンド開発者向けに開発されており、サードパーティの依存関係やパッケージを追加することなく、すぐにテストの作成を始められます。 これは、Selenium といった他のツールにはない利点です。このチュートリアルでは、Cypress を使用して API テストを行う方法をご紹介します。また、このガイドに表示されているコードは全て、コピペが可能ですので是非、ガイド内に提供されているコードをご自由にお使い下さい。

本記事では以下のトピックを扱います。

  1. Cypress フレームワークのセットアップ
  2. Cypress で API に対して HTTP 呼び出しを行う方法
  3. Cypress の cy.request() メソッドの使い方

前提条件

このチュートリアルを進めるには、以下の準備が必要です。

  • JavaScript と Git/GitHub の基礎を理解する
  • Node.js (バージョン 10.3 以上) をローカル システムにインストールする
  • CircleCI アカウントを用意する
  • GitHub アカウントを用意する

Cypressとは?Cypress を使った API テストの概要

Cypressはスタンドアロン型のフロントエンド テスト ツールであり、実行時には Web アプリケーションの代わりに HTTP リクエストを行います。 一見すると Cypress がこうしたリクエストをブラウザーから送信しているように見えますが、実際には API サーバーへの HTTP リクエストを行うエンジンとして Node.js を使用します。 また、サーバーから受け取った応答を返す際にも Node.js を使用しています。

Cypress の HTTP 呼び出しのアーキテクチャ図

: Cypress では、メソッド cy.request() を公開することでフレームワーク内から HTTP リクエストを送信します。 本チュートリアルでは、Cypress を使ってエンドポイントをテストする際に、このメソッドを使用します。

ディレクトリを初期化して Cypress をセットアップする

まず、ターミナルで以下のコマンドを実行して、空のディレクトリを作成し、空の Node プロジェクトを初期化します。

mkdir testing-apis-with-cypress && cd testing-apis-with-cypress

このコマンドでディレクトリを作成したら、以下のコマンドを実行してデフォルト設定の Node.js プロジェクトを作成します。 なお、デフォルト設定の変更については、このチュートリアルの後半で扱います。 テストの作成は、初期化した Node プロジェクトで行います。

npm init -y

npm init -y を実行すると、デフォルト設定の Node プロジェクトが作成されますが、プロジェクトの package.json ファイルの中身をカスタマイズするためのメッセージは表示されません。 「-y」なしの npm init を実行すると、Node プロジェクトのプロパティを設定するためのメッセージが表示されるため、package.json ファイルの中身が変わってしまうおそれがあるので注意してください。

ディレクトリの初期化が完了したら、Cypress フレームワークをインストールします。 Cypress のインストール方法は、他の npm パッケージのインストールと同じなので、以下のどちらのコマンドでもインストールできます。

npm install cypress

または

yarn add cypress

Cypress のインストールが完了したら、次は Cypress フレームワークを初期化します。 このプロセスでは、デフォルトの Cypress ディレクトリを作成します。このディレクトリで、テストの作成やパッケージの追加 (必要な場合) を行います。

ターミナルで、コマンド cypress open を実行します。 このコマンドを実行すると、Cypress が初期化され、Cypress のデフォルトのディレクトリとファイルが作成されます。

注: うまく行かない場合は、Cypress をグローバルにインストールしてみることをお勧めします。

Cypress の初期化

Git をセットアップして CircleCI にプッシュする

テストの作成に取りかかる前に、CircleCI をセットアップする必要があります。 まず、以下のコマンドを実行してプロジェクトの Git リポジトリを初期化します。

git init

次に、ルート ディレクトリに .gitignore ファイルを作成します。 このファイル内に node_modules を追加して、npm で生成されたモジュールがリモート リポジトリに追加されないように設定します。 次の手順として、コミットを追加し、プロジェクトを GitHub にプッシュします。

CircleCI にログインして、[Projects (プロジェクト)] に移動します。 お使いの GitHub ユーザー名または組織に関連付けられているすべての GitHub リポジトリが一覧表示されます。 CircleCI でセットアップするリポジトリを見つけます。 このチュートリアルでは、api-testing-with-cypress プロジェクトを使用します。 [Projects (プロジェクト)] ダッシュボードで、使用するリポジトリの [Set Up Project (プロジェクトのセットアップ)] を選択します。 既存の設定ファイルを使用するオプション ([Fastest (最速)]) を選択します。

start-building-page

ビルド プロセスが開始されますが、パイプラインは失敗します。これは、カスタマイズした .circleci/config.yml ファイルをまだ GitHub に追加していないからです。

start-building-prompt

CI パイプラインを作成する

CircleCI パイプラインのセットアップが完了したら、続いては CircleCI をローカル プロジェクトに追加します。 まず、ルート ディレクトリに .circleci というディレクトリを作成します。 このディレクトリの中に config.yml ファイルを作成します。 config.yml に以下の設定を追加します。

version: 2
jobs:
  build:
    docker:
      - image: cypress/base:14.16.0
        environment:
          ## 出力を色付け
          TERM: xterm
    working_directory: ~/repo
    steps:
      - checkout
      - restore_cache:
          keys:
            - v1-deps-{{ .Branch }}-{{ checksum "package.json" }}
            - v1-deps-{{ .Branch }}
            - v1-deps
      - run:
          name: 依存関係のインストール
          command: npm ci
      - save_cache:
          key: v1-deps-{{ .Branch }}-{{ checksum "package.json" }}
          # NPM モジュールと、Cypress バイナリ格納ディレクトリをキャッシュする
          paths:
            - ~/.npm
            - ~/.cache
      - run: $(npm bin)/cypress run
      - store_artifacts:
          path: ~/repo/api-testing-with-cypress

この設定ファイルでは、環境から Cypress Docker イメージをプルし、依存関係の保存済みキャッシュがあるかどうかを確認しています。

キャッシュが存在する場合は、キャッシュをリストアします。そして、save_cache の実行時点で変更が検出された場合にのみ、アプリケーションの依存関係を更新します。 続いて、api-testing-with-cypress の Cypress テストを実行し、キャッシュされたアイテムが ~/repo/api-testing-with-cypress ディレクトリ内のアーティファクトに保存されます。

変更を GitHub にプッシュすると、CircleCI によって自動的にビルド プロセスが開始されます。 ここでも、まだテストを作成していないため、パイプラインは再び失敗します。 後ほどテストを追加したあとで、再度実行することにしましょう。 CircleCI のダッシュボードでは、リポジトリでテストを実行していなくても、作成されたパイプラインと実行結果を確認できます。

Cypress を使い始める

このチュートリアルでは、CircleCI があらかじめ作成して Heroku にホストしている API をアプリケーションのテストに使用します。 そのためには、まず、テストで使用する API URL (Cypress ではこれを baseUrl と呼びます) を Cypress に認識させる必要があります。

baseUrl を設定する

Cypress フレームワークには、Cypress の初期化プロセスで生成される設定ファイル cypress.json が用意されています。 cypress.json ファイルは、指定するすべての設定変数を格納するものであり、baseUrl もこのファイルで設定します。 これによって、テストを実行する際にいちいち URL を入力する必要がなくなります。 baseUrl は、以下のコード スニペットのように、Heroku API URL を指す設定変数として cypress.json ファイル内で設定します。

{
   "baseUrl": "http://todo-app-barkend.herokuapp.com/"
}

コマンドを設定する

テスト URL の準備ができたので、ターミナルからテストを簡単に実行できるように準備しましょう。 そのために、package.json ファイル内の “scripts” セクションにスクリプトを 1 つ追加します。 具体的には、package.json ファイルの “scripts” セクションに以下の test コマンドを追加します。

"scripts": {
   "test": "cypress open"
 },

このコマンドは、テストの実行時に Cypress でヘッドレス モードを使用せずブラウザーを開くように設定しています。

package.json ファイルにスクリプトを追加すると、コマンドやスクリプトを自動化でき、自分でターミナルに入力する必要がなくなります。 また、これらのコマンドやスクリプトをプログラムが理解できる形でパッケージ化すれば、npm で実行することもできます。

Cypress でテストを作成する

フロントエンド テスト ツールである Cypress は、Cypress テストの書き方の手本となるファイルやディレクトリを豊富に生成してくれます。 ただ、このチュートリアルでは、それらは無視することにします。

Cypress の初期化と CircleCI パイプラインの設定が完了したので、いよいよテストを作成しましょう。

最初の Cypress API テストを作成する

前半で説明したとおり、Cypress では内部で Node.js を使用して HTTP リクエストをトリガーし応答を Cypress に戻すことで、アサーションや、想定される呼び出しの実行結果を検証します。 最初のテストでは、サンプルの ToDo アプリケーションに対して GET リクエストを送信し、実際に ToDo 項目が API に返されるかを確認することにしましょう。 このテストを始めるには、cypress/integration/ ディレクトリにあるものをすべて削除しておく必要があります。 このディレクトリには、Cypress の初期化で生成されたスキャフォールドが格納されています。 この cypress/integration/ 内に、api-tests という名前のディレクトリを作成します。 Cypress にこのテスト ディレクトリのアクションを理解させるために、cypress.json ファイルに以下の設定値を追加します。

  {
   "integrationFolder": "cypress/integration/api-tests"
  }

次は、api-tests ディレクトリ内に todo.spec.js ファイルを作成します。このファイルにテストを記述します。 ここでのポイントとして、Cypress はスタンドアロンであるため、API のテストに外部の依存関係が一切必要ありません。

todo.spec.js ファイルを開き、ToDo アプリケーションへの API GET リクエストに対するテストを設定しましょう。 次のコードを追加します。

describe('TODO api testing', () => {
   let todoItem;
   it('fetches Todo items - GET', () => {
       cy.request('/todos/').as('todoRequest');
       cy.get('@todoRequest').then(todos => {
           expect(todos.status).to.eq(200);
           assert.isArray(todos.body, 'Todos Response is an array')
       });
   });
});

この例では、cy.request() メソッドに baseUrl を渡しています。 このメソッドによって、ホストされている API エンドポイントに対して ToDo 項目を取得する GET リクエストを送信し、API がテストによって呼び出されることを検証します。

: cy.request() は、HTTP リクエスト処理が指定されなかった場合、デフォルトで GET リクエストを行います。 そのため、API の GET リクエストを行うように設定する必要はありません。

Cypress API テストを実行する

最初のテストを実行して問題なく動作するか確認するために、ターミナルで npm test コマンドを実行します。 npm test コマンドは、チュートリアルの中盤で package.json に定義したものです。 Cypress ダッシュボードが開きます。

Cypress ダッシュボード

テスト実行コマンドを実行すると、追加したテスト (spec ファイル) が Cypress ダッシュボードに表示されます。 目的のテストを選択し、Cypress が実行する様子を観察しましょう。

テスト実行中の Cypress ダッシュボード

テストの実行が正常に完了し、すべての ToDo 項目を取得できたことがダッシュボードに表示されます。 Cypress はデフォルトでブラウザーで実行されるため、テストから返されたすべての要素を詳しく検証することができます。

画面左側で、返された配列が表示されている最後のアサーションをクリックします。 クリックすると、出力がコンソールに表示されます。 また、ウィンドウを右クリックして要素検証/調査オプションを選択すると、ブラウザーの開発者向けツールが開きます。 [Console (コンソール)] タブをクリックすると、テストでアサーションした項目の配列が表示されます。 API とテストが正常に機能していることを確認できたので、ひとまずテストは成功です。

さらにテストを作成して追加する

Cypress でのテストの追加に慣れたところで、さらにテストを追加してみましょう。 例として、新しい ToDo 項目を追加するテストと、ToDo 項目を削除するテストを作成してみます。

   it('deletes Todo items - DELETE', () => {
       cy.request('DELETE', `/todos/${todoItem}`).as('todoRequest');
       // ID が 9 である ToDo 項目を削除する
       cy.get('@todoRequest').then(todos => {
           expect(todos.status).to.eq(200);
           assert.isString(todos.body, 'todo deleted!')
       });
   });

   it('Adds Todo item - POST', () => {
       cy.request('POST', '/todos/', { task: "run tests" }).as('todoRequest');
       // ToDo 項目の名前を定義して新規項目を追加する
       cy.get('@todoRequest').then(todos => {
           expect(todos.status).to.eq(200);
           cy.wrap(todos.body).should('deep.include', {
               task: 'run tests',
               completed: false,
           });
       });
   });

このコード スニペットでは、cy.request() で HTTP リクエストの型を宣言しています。 新しい ToDo 項目を作成する POST リクエストのbody といった他の引数も、このコマンドで宣言します。 これらのテストを実行して、API で ToDo 項目を作成し、作成されたすべての ToDo 項目を取得し、ToDo 項目を削除できていることを確認しましょう。 テストが成功すれば、 API は正常に機能しています。

続いては、既存の CircleCI パイプラインでテストに合格することを確認する必要があります。 CircleCI の初期設定は既に行っているので、後は変更をコミットして GitHub にプッシュするだけです。 これで、CircleCI によりテストが自動的に実行されます。

CircleCI での実行成功

このテストも成功しました! すべてのテストに合格できました。

おわりに

このチュートリアルでは、Cypress をセットアップして、API テストを実行する方法をご紹介しました。 テスト用に baseUrl を設定する方法を解説し、テスト フレームワークのディレクトリを設定しました。 また、cy.request() を使ってさまざまな HTTP 処理を行う方法と Cypress のテスト ランナーの使い方についても解説しました。 このチュートリアルで紹介した内容が、みなさまのお役に立てば幸いです。 これからもアプリケーションの開発を楽しみましょう!


Waweru Mwaura 氏は品質工学を専門とするソフトウェア エンジニアです。生涯学習の実践者という顔も持ち、 Packt で執筆者を務めながら、工学や金融、テクノロジーの書籍を愛読しています。 Mwaura 氏の詳しい情報については、https://waweruh.github.io/ をご覧ください。