📝

DatadogブラウザテストをTerraformで管理する

に公開

こんにちは。株式会社シータグCTOの @y_okady です。

シータグでは、自社サービスであるBtoB向けクラウド受発注サービス 受注ハック のサーバー監視・分析に Datadog を利用しています。トラブルシューティングの効率化を主な目的とし、ログ・セッションリプレイ・モニタリングといった機能を活用しています。

一方、ブラウザテストには Autify を利用していましたが、Datadogに一本化すべく Datadog Synthetics Testsのブラウザテスト機能 に乗り換えることにしました。

Datadogブラウザテスト導入当初はAutifyと同じように、レコーダーと設定画面を用いてテストを作成していました。しかし、Autifyほどノーコードで済む部分が多くはなく、処理を共通化して再利用する機能もないため、テストケースごとに多くのコードを書く必要があります。これではメンテナンスが大変だということで調べてみたところ、Terraform でDatadogブラウザテストを管理できることがわかりました。

https://docs.datadoghq.com/ja/synthetics/guide/manage-browser-tests-through-the-api/

この記事では、DatadogブラウザテストをTerraformで管理する方法をサンプルコードを交えてご紹介します。

TerraformによるDatadogブラウザテスト管理の仕組み

受注ハックでは、インフラの構成管理にIaCツールであるTerraformを利用しています。HCL(.tfファイル)でインフラの構成を定義し、terraform plan コマンドで差分を確認した上で terraform apply コマンドでインフラに反映するという流れは、Datadogブラウザテストの管理においても同様です。

HCLでテストケースを定義し、terraform plan コマンドで差分を確認した上で、terraform apply コマンドでDatadogに反映します。ブラウザテストの実行や、実行に関する設定はDatadogの画面上で行います。

初期設定

TerraformでDatadogブラウザテストを管理するためにはDatadogプロバイダーを利用します。Datadogプロバイダーの利用には、APIキー、アプリケーションキー、サイトURL(AP1の場合は https://ap1.datadoghq.com)が必要です。

main.tf
terraform {
  required_providers {
    datadog = {
      source = "DataDog/datadog"
    }
  }
}

provider "datadog" {
  api_key = var.datadog_api_key
  app_key = var.datadog_app_key
  api_url = var.datadog_api_url
}

# 共通の処理のためのモジュール(後述)
module "common_steps" {
  source = "./common_steps"
}

共通の変数・処理の定義

Terraformでテストケースを管理するにあたり、テストのメンテナンス性や独立性を考慮し、1ファイル1テストケースの構成を採用しました。テストケース間で共通の変数はvariables.tfに、共通の処理はcommon_steps/main.tfに定義します。共通の処理はモジュールとして扱います。

共通の処理でJavaScriptを実行する場合は、JavaScriptファイルを別途作成して読み込むようにしています。例えば以下の例では、ログイン処理は画面上での操作ではなくログインAPIを直接実行するようにし、テスト実行時間を短縮しています。

variables.tf
locals {
  type       = "browser"
  status     = "paused"
  device_ids = ["chrome.laptop_large"]
}
common_steps/main.tf
output "login" {
  value = {
    name = "ログインする"
    type = "assertFromJavascript"
    params = {
      code = file("${path.module}/js/login.js")
    }
  }
}

output "show_product" {
  value = {
    name = "商品一覧画面を表示する"
    type = "goToUrl"
    params = {
      value = "<商品一覧画面URL>"
    }
  }
}
common_steps/js/login.js
return (async () => {
  await fetch("<ログインAPI URL>", {
    method: "POST",
    credentials: "include",
    body: JSON.stringify({
      email: "<メールアドレス>",
      password: "<パスワード>",
    }),
  });
  return true;
})();

テストケースの作成

テストケースを定義するファイルでは、共通の変数・処理と、独自の処理を組み合わせてテストケースを組み立てます。HTML要素の特定にはXPathまたはCSSセレクタを利用します。

商品を登録できる.tf
resource "datadog_synthetics_test" "商品を登録できる" {
  name = "商品を登録できるできる"

  type       = local.type
  status     = local.status
  device_ids = local.device_ids

  request_definition {
    method = "GET"
    url    = "<ログイン画面URL>"
  }

  # ログインする
  browser_step {
    name = module.common_steps.login.name
    type = module.common_steps.login.type
    params {
      code = module.common_steps.login.params.code
    }
  }

  # 商品一覧画面を表示する
  browser_step {
    name = module.common_steps.show_product.name
    type = module.common_steps.show_product.type
    params {
      value = module.common_steps.show_product.params.value
    }
  }

  browser_step {
    name = "新規登録ボタンをクリックする"
    type = "click"
    params {
      element_user_locator {
        value {
          type  = "xpath"
          value = "//button[text()=\"商品を新規登録\"]"
        }
      }
    }
  }

  browser_step {
    name = "商品名を入力する"
    type = "typeText"
    params {
      value = "テスト商品"
      element_user_locator {
        value {
          type  = "css"
          value = "form *[name=\"product_name\"]"
        }
      }
    }
  }

  browser_step {
    name = "登録ボタンをクリックする"
    type = "click"
    params {
      element_user_locator {
        value {
          type  = "xpath"
          value = "//form//button[text()=\"登録\"]"
        }
      }
    }
  }

  browser_step {
    name = "商品名をチェックする"
    type = "assertFromJavascript"
    params {
      code = "return element.textContent === \"テスト商品\";"
      element_user_locator {
        value {
          type  = "css"
          value = "*[class^=\"ProductName__\"]"
        }
      }
    }
  }
}

テストケースを定義できたら、terraform plan コマンドで差分を確認した上で、terraform apply コマンドでDatadogに反映します。

Datadogに反映したテストケースは、Datadog画面上で手動実行することも、GitHub ActionsなどのCIから実行することも可能です。受注ハックではGitHub Actionsを利用し、アプリケーションをステージング環境にデプロイした後にブラウザテストを実行するようにしています。

まとめ

Autifyのようなテストプラットフォームを利用することで、テスト環境を自前で構築・管理することなくノーコードで簡単にテストケースを作成・実行できるようになります。また、テスト環境を自前で構築・管理し、テストコードを書く場合はCypressなどのテストフレームワークが便利です。テストコードをGitHubなどでバージョン管理することも可能です。

Datadogブラウザテストは、Autifyと比べるとテストプラットフォームとしては機能が劣る部分もありますし、Cypressなどのテストフレームワークとプログラミング言語を利用する方法と比べるとHCLによるテストケースの作成は自由度が下がります。

しかし、それぞれのいいとこ取りをできるのがDatadogブラウザテストの強みだと感じています。テスト環境を自前で構築・管理することなく、テストコードを書いてGitHubなどでバージョン管理することも可能です。

Datadogを利用されている方や導入を検討されている方にこの記事を読んでいただき、ブラウザテストの選択肢の一つにDatadogもあるんだよということを知っていただけると幸いです。

株式会社シータグ

Discussion