見出し画像

⑦Azure DevOpsを利用してAllure x Pytestを使ったテスト自動化環境構築(Azure Pipelinesコーディング解説編)

SHIFT Group 技術ブログ

はじめに

こんにちは、自動化エンジニアの竹川です。

前回のAzure Pipelines構築編はいかがでしたか?今回も引き続き「Azure DevOpsを利用してAllure x Pytestを使ったテスト自動化環境構築」をご紹介したいと思います。

本記事の目的

前回の章では「Azure Repos」「Azure Pipelines」「Azure Artiacts」を使ったパイプラインの構築方法ついて解説させていただきました。
今回の章では「Azure Pipelines」の「⑥Azure DevOpsを利用してAllure x Pytestを使ったテスト自動化環境構築(Azure Pipelines構築編)」のサンプルプログラムに内容されている「azure-pipelines.yml」の パイプラインのコーディングについて詳しく解説をさせていただきます。

Azure Pipelinesコーディング解説

1. triggerについて

triggerはパイプラインを実行するイベントを設定するものです。サンプルの例ではmasterと記載しているのでmasterブランチにpushされた時にパイプラインが実行されます。

※triggerの詳細についてこちらをご参照ください。

trigger:
- master

pool: PytestPoc-Readiness-Pool

name: $(Year:yy)$(DayOfYear)$(Rev:r)
variables:
  majorVer: '1.0.0'

2. stageについて

stageはジョブを整理するためのもので上位にStagesがあり、その中に各Stageを管理します。Stageの中にはjobs、その配下にはjobがあります。
このように階層構造を持たせる事でパイプラインでのジョブの実行条件やどこまで何を実行するか整理が可能となります。

※stageの詳細についてこちらをご参照ください。

stages:
  - stage: test
    jobs:
      - job: job_test

3. testステージについて

stage:testの解説をいたします。このステージはテスト実行を管理するステージとして定義してます。stageの配下にjobs > jobがありますね。
jobに実際の処理を書いていきます。displayNameはAzure Pipelinesで表示される名前となります。わかりやすい名前を付けると不具合があった場合に識別しやすくなります。

次にpowershellというタグがありますね。こちらにpytestコマンドでテスト実行するための処理が記載されています。コマンド書いてあるもののこれだと初めての方だと良くわかりませんね・・・。 実際には$(System.DefaultWorkingDirectory)という変数に作業ディレクトリが格納されているのでこのディレクトリを軸にコマンドが実行されます。

pytestコマンドの--alluredir というオプションにはpytestで実行したテスト結果のデータが保存されます。次にpublishというタグに--alluredirで指定したディレクトリが記載されてますね。 これがAirtifactsに成果物をアップロードする処理となります。artifactタグに名前を付ける事で識別できるようになります。このタグは後ほどAPIで引き出すための条件になるため、名前はわかりやすい名前を設定してください。

  - stage: test
    jobs:
      - job: job_test
        displayName: 'job_test'
        workspace:
          clean: all
        continueOnError: true 
        steps:
          - checkout: self
            clean: true
          # Pytest実行
          - powershell: py -m pytest -v -s ".\tests" --alluredir=".\allure_results"
          # AllureデータをArtifactsへアップロード
          - publish: "$(System.DefaultWorkingDirectory)\\allure_results"
            artifact: test_allure_results

4. history_copyステージについて

このステージはAllureの履歴データをマージするための処理です。 端的に言うと前回成功したパイプラインのAllureデータをAPIでダウンロードして、今回実行したテスト結果のデータとマージをする処理をしています。

実行しているAPIは以下2つとなります。

Latest - GetのAPIで対象プロジェクトの最終実行されたPipelineの情報取得します。属性情報の中に次に実行するAPIで利用するビルドIDを取得するためです。

Builds - ListのAPIで指定したビルドIDのアーティファクト名がpages_publicとビルド情報を取得します。ビルド情報にはアーティファクトのダウンロードURLが含まれているので そのURLから前回のパイプラインでアップロードしたAllureのデータをダウンロードするためです。

  - stage: history_copy
    jobs:
      - job: job_history_copy
        displayName: 'history_copy'
        steps:
          - checkout: none
          - powershell: |
              # ヘッダパラメータ生成
              $headerParams = @{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$(System.AccessToken)")) }
              # Pipelineの最終ビルド情報取得
              $res = Invoke-WebRequest -Headers $headerParams -Uri "$(System.TeamFoundationCollectionUri)$(System.TeamProject)/_apis/build/latest/$(System.DefinitionId)?api-version=7.1-preview.1"
              # ビルドID取得
              $latestBuildId = ($res.Content | ConvertFrom-Json).id 
         
              try {
                # 指定ビルドIDのArtifactsのダウンロードURL取得
                $res = Invoke-WebRequest -Headers $headerParams -Uri "$(System.TeamFoundationCollectionUri)$(System.TeamProject)/_apis/build/builds/${latestBuildId}/artifacts?artifactName=pages_public&api-version=4.1"
                # ダウンロードURL取得
                $downdloadUrl = ($res.Content | ConvertFrom-Json).resource.downloadUrl
                # アーティファクトダウンロード
                Invoke-WebRequest -Headers $headerParams -Uri $downdloadUrl -OutFile ".\pages_public.zip"
                # ダウンロードしたアーティファクトを解凍
                Expand-Archive ".\pages_public.zip"
                # 履歴用ディレクトリ作成
                New-Item ".\allure_results\history" -ItemType Directory
                # Allure履歴をコピー
                Copy-Item -Force -Path ".\pages_public\pages_public\history\*" -Destination ".\allure_results\history"
              } catch [System.Net.WebException] {
                  Write-Host "アーティファクトが取得できませんでした。"
              }

5. generate_reportステージについて

このステージはtestステージで生成したpytestのテスト結果をHTML形式のレポートを作成し、Artifactsへアップロードする処理です。
allure generateコマンドを実行するとallure_reportというディレクトリにレポートが生成されるのでWindows Serverへログインして 実行してみると理解度が深まるかもしれません。

  - stage: generate_report
    jobs:
      - job: job_generate_report
        displayName: 'job_generate_report'
        steps:
          - checkout: none
          # Allureレポート生成
          - powershell: allure generate -c ".\allure_results" -o ".\allure_report"
          # AllureレポートデータをArtifactsへアップロード
          - publish: "$(System.DefaultWorkingDirectory)\\allure_results"
            artifact: generate_report_allure_results
          # AllureレポートをArtifactsへアップロード
          - publish: "$(System.DefaultWorkingDirectory)\\allure_report"
            artifact: generate_report_allure_report

6. pagesステージについて

このステージはgenerate_reportステージで生成されたallureのレポートを「Azure Storage」へアップロードする処理です。
ここでのポイントとしては「task: AzureFileCopy@4」部分です。これはAzure file copyというタスクで ローカルにある静的ファイルをAzure Storageへアップロードしています。このタスクは内部的にはaz copyコマンドが実行されています。

※「Python x Allure環境構築編」でAzモジュールをインストールをしたと思いますが、これを怠るとこのタスクはエラーになりますのでご注意ください。

  - stage: pages
    jobs:
      - job: job_pages
        displayName: 'job_pages'
        steps:
          - checkout: none
          - powershell: |
              # Allureレポートデータ格納用フォルダ作成(public)
              if ( -not (Test-Path -Path ".\public" -PathType container) ) {
                New-Item public -ItemType Directory
              } else {
                 Get-ChildItem ".\public" -Include *.* -Recurse | del
              }

              # Allureレポートをpublicフォルダへコピー
              Copy-Item -Force -Recurse -Path ".\allure_report\*" -Destination ".\public"
          # Allureレポート(publicフォルダ)をartifactsへアップロード
          - publish: "$(System.DefaultWorkingDirectory)\\public"
            artifact: pages_public
          # Allureレポートを「Azure Storage」へアップロード
          - task: AzureFileCopy@4
            inputs:
              SourcePath: '$(System.DefaultWorkingDirectory)/public'
              azureSubscription: 'SC-Pytest-PoC'
              Destination: 'AzureBlob'
              storage: 'pytestpoc'
              ContainerName: '$web'

7. Pipelineの結果通知ついて

pagesステージ内のタスクですが、pagesステージは処理が多いため、個別で解説させていただきます。 こちらのタスクはパイプラインの結果を通知するための処理となります。

このタスクのポイントとしてはTeamsアプリのIncoming Webhookで発行したurlを 設定する事とmsgタグでテンプレートを設定する事です。

用途によってはステージ毎に通知する事や個別に送信テンプレートを設定する事も可能ですので要件に沿って実装すると良いと考えています。

          # Pipeline結果をTeamsへ通知
          - task: PostToOffice365Connector@1
            inputs:
              url: 'https://xxxxx.webhook.office.com/webhookb2/xxxxx/IncomingWebhook/xxxxxx/xxxxx'
              title: 'Azure Pipelines Complate'
              msg: |
                * RequestedFor : $(Build.RequestedFor)
                * Branch:$(Build.SourceBranch)
                * Last Commit ID:$(Build.SourceVersion)  
                * Last Commit Comment:$(Build.SourceVersionMessage)  
                
                [result link]($(System.TeamFoundationCollectionUri)$(System.TeamProject)/_build/results?buildId=$(Build.BuildId))

                [allure report](https://xxxxx.xxxx.web.core.windows.net/public/)

終わりに

7回にわたり「Azure DevOpsを利用してAllure x Pytestを使ったテスト自動化環境構築」についてご紹介させていただきました。
CI/CDの技術はクラウドサービス、利用する言語、アプリケーション、ツールの種類が多くどれを使っていいのか迷ってしまいますよね!?

実際に筆者もCI/CDを導入する際に何を使ったら良いか手当たり次第にインターネットの記事をあさっては動かして試行錯誤をしていました。
悪い例としてはサポートが終了していたり、バグが改修されていないなどがあり、時間をかけて調べたけど使えなかったものがいくつかありました。

こういった苦労した結果をナレッジとして残したいと思い、今回ブログにさせていただきました。 これからも新しい技術などを研究した結果を残して皆さんのお役に立てるようにできたらと思います。

ブログを最後まで読んでいただいてありがとうございました。また、この記事が参考になった場合は「いいね!」をつけていただけると今後のモチベーションがあがりますので宜しくお願いいたします。


執筆者プロフィール:Shinya Takekawa
前職ではERPパッケージのクラウドサービスの運用を3年経験 SHIFTでは、自動化エンジニアとして入社し、RPA、CI/CD、テストプログラム開発など案件に応じて従事しています。
得意な事としてはTerraform、Ansibleを使ったインフラ構築の自動化技術です。 CI/CDを中心とした自動化の技術に興味があり、日々勉強をしています。 研究した内容を広めて皆様に貢献できたらと思っています。


みんなにも読んでほしいですか?

オススメした記事はフォロワーのタイムラインに表示されます!
SHIFT Group 技術ブログ
「無駄をなくしたスマートな社会の実現」を目指し、ソフトウェア製品の開発、運用、マーケティングなどあらゆる立場から携わるSHIFT Groupの公式note。エンタメ・ゲーム業界から、Web系、金融/製造/小売りなどのエンタープライズ業界まで広い知見を活かした情報を発信しています。