初心者向けのE2Eテストの書き方ガイド

このチュートリアルでは、GitLab Community EditionとGitLab EnterpriseEditionのエンドツーエンド_(e2e)_テストの作成について学びます。

このチュートリアルの終わりには、以下のことができるようになります:

  • エンド・ツー・エンドのテストが必要かどうかを判断します。
  • qa/内のディレクトリ構造を理解しましょう。
  • ログイン機能を検証する基本的なエンドツーエンドのテストを書いてください。
  • 不足しているページオブジェクトライブラリを開発します。

テストを書く前に

テストを書く前に、GitLab Development Kit(GDK)が仕様を実行するように設定されている必要があります。 エンドツーエンドのテストです:

  • qa/ ディレクトリ内部にあります。
  • 独立かつべきであること。
  • リソース(プロジェクト、イシュー、ユーザーなど)をアドホックに作成できます。
  • UIとAPIのインターフェイスをテストし、APIを使用してUIテストを効率的に設定します。
ヒント:詳細については、エンドツーエンド・テストのベストプラクティスを参照してください。

エンド・ツー・エンドのテストが必要かどうかの判断

GitLab Community EditionとGitLab Enterprise Editionの両方のプロジェクトで、エンドツーエンドテストを書く前に特定の機能のコードカバレッジをチェックしてください。 ユニット、機能、インテグレーションの各レベルで十分なテストカバレッジが存在しますか? もし「はい」と答えたなら、エンドツーエンドテストは必要ありません

GitLab におけるレベルごとのテストのディストリビューションについては、Testing Levelsを参照ください。

  • テスト・レベルに関する文書の「正しいレベルでテストする方法」セクションを参照してください。
  • 機能が変更される頻度をレビュアーがレビューします。 あまり頻繁に変更されない安定した機能は、低レベルのテストですでにカバーされている場合、エンドツーエンドのテストでカバーする価値がないかもしれません。
  • 最後に、提案されたテストについて、その機能や下位レベルのテストの実装に携わる開発者と議論してください。
注意:GitLab Community EditionとGitLab Enterprise Editionの両方のカバレッジプロジェクトで、この機能に対して以前に書かれたテストがないか確認してください。 コードカバレッジを分析するためには、どのアプリケーションファイルが特定の機能を実装しているかを理解する必要があります。
注意:このチュートリアルでは、ログインのエンドツーエンドテストを書きますが、これは、ほとんどのエンドツーエンドフローの最初のステップであり、最も理解しやすいからです。

DevOpsステージの特定

GitLab QAのエンドツーエンドテストは、DevOpsライフサイクルのさまざまなステージごとに整理されています。ステージごとにテストを配置する場所を決め、テストがどの機能に属するかを決定し、ステージの下のサブディレクトリに配置します。

DevOps lifecycle by stages

: テストが Enterprise Edition のみの場合、テストはfeatures/eeディレクトリに作成されますが、同じ DevOps ライフサイクル形式に従います。

スケルトン・テストの作成

このチュートリアルの最初の部分では、Manageステージが所有するloginをテストします。qa/specs/features/browser_ui/1_manage/loginの内部で、ファイルbasic_login_spec.rbを作成します。

外側のcontext ブロック

スペックには、DevOpsのステージを示す内部context

# frozen_string_literal: true

module QA
  context 'Manage' do

  end
end

describe ブロック

外側のcontextの内部には、テストする機能を記述します。この場合、Login

# frozen_string_literal: true

module QA
  context 'Manage' do
    describe 'Login' do

    end
  end
end

it ブロック(例)

すべてのテストスイートには、少なくとも一つのit ブロック(例)が含まれています。 エンドツーエンドのテストを書き始める良い方法は、テストケースの記述をit ブロックとして書くことです:

module QA
  context 'Manage' do
    describe 'Login' do
      it 'can login' do

      end

      it 'can logout' do

      end
    end
  end
end

テストを書く

重要なのは、”何をテストするのか?”、そしてさらに重要なのは、”どのようにテストするのか?”ということです。

ログインしてください。

# frozen_string_literal: true

module QA
  context 'Manage' do
    describe 'Login' do
      it 'can login' do
        Flow::Login.sign_in

      end

      it 'can logout' do
        Flow::Login.sign_in

      end
    end
  end
end

スペックを実行した後、テストはログインして終了するはずです。それから、”何をテストするのか?”という質問に答えなければなりません。

# frozen_string_literal: true

module QA
  context 'Manage' do
    describe 'Login' do
      it 'can login' do
        Flow::Login.sign_in

        Page::Main::Menu.perform do |menu|
          expect(menu).to be_signed_in
        end
      end

      it 'can logout' do
        Flow::Login.sign_in

        Page::Main::Menu.perform do |menu|
          menu.sign_out

          expect(menu).not_to be_signed_in
        end
      end
    end
  end
end

何をテストするのですか?

  1. ログインできますか?
  2. ログアウトできますか?

どうやってテストするの?

  1. ユーザーアバターがトップナビゲーションに表示されるかどうかを確認します。
  2. ユーザーアバターがトップナビゲーションに表示されないか確認してください。

コードの複製を削除

sign_inへの呼び出しが重複しているので、テストのセットアップにbefore ブロックを使うようにテストをリファクタリングしてください。

# frozen_string_literal: true

module QA
  context 'Manage' do
    describe 'Login' do
      before do
        Flow::Login.sign_in
      end

      it 'can login' do
        Page::Main::Menu.perform do |menu|
          expect(menu).to be_signed_in
        end
      end

      it 'can logout' do
        Page::Main::Menu.perform do |menu|
          menu.sign_out

          expect(menu).not_to be_signed_in
        end
      end
    end
  end
end

before ブロックは、基本的にbefore(:each) で、各例の前に実行され、各テストの開始時にログインするようにします。

リソースとページオブジェクトを使用したテストセットアップ

次に、Login以外のものをテストしてみましょう。Planステージが所有するイシューをテストするため、qa/specs/features/browser_ui/3_create/issuesissues_spec.rbというファイルを作成します。

# frozen_string_literal: true

module QA
  context 'Plan' do
    describe 'Issues' do
      let(:issue) do
        Resource::Issue.fabricate_via_api! do |issue|
          issue.title = 'My issue'
          issue.description = 'This is an issue specific to this test'
        end
      end

      before do
        Flow::Login.sign_in
        issue.visit!
      end

      it 'can close an issue' do
        Page::Project::Issue::Show.perform do |show|
          show.click_close_issue_button

          expect(show).to be_closed
        end
      end
    end
  end
end

以下の重要な点に注意してください:

  • この例の冒頭ではpage/issue/show.rb
  • 私たちのテストは、必要なときに必要なものだけを製造します。
  • イシューは時間を節約するためにAPIを通じて作成されます。
  • GitLabはインスタンス変数よりもlet()ベストプラクティスを参照ください。
  • be_closed はまだpage/project/issue/show.rb には実装されていませんが、次のステップで実装される予定です。

イシューはリソースとして作成されます。リソースはUIやAPIを通して作成できるGitLabのエンティティです。 他の例としては、以下のようなものがあります:

Pagesオブジェクトの書き込み

ページオブジェクトは、GitLab 内のページを表すスイート内のクラスです。ログインページがその一例です。イシュー表示ページ用のページオブジェクトはすでに存在しているので、closed? メソッドを追加します。

module Page::Project::Issue
  class Show
    view 'app/views/projects/issues/show.html.haml' do
      element :closed_status_box
    end

    def closed?
      has_element?(:closed_status_box)
    end
  end
end

次に、ビュー内部で要素closed_status_box を定義し、Page Object から見えるようにします。

-#=> app/views/projects/issues/show.html.haml
.issuable-status-box.status-box.status-box-issue-closed{ ..., data: { qa_selector: 'closed_status_box' } }

スペックの実行

スペックを実行する前に確認してください:

  • GDKがインストールされています。
  • GDKはローカルではポート3000で動作しています。
  • 追加のRSpecメタデータタグは適用されていません。
  • 作業ディレクトリはGDK GitLabインストール内部qa/

スペックを実行するには、以下のコマンドを実行します:

bundle exec bin/qa Test::Instance::All http://localhost:3000 -- <test_file>

<test_file>

  • qa/specs/features/browser_ui/1_manage/login/login_spec.rb Loginの例を実行するとき。
  • qa/specs/features/browser_ui/2_plan/issues/issue_spec.rb イシューの例を実行するとき。