演習: UI テストをローカルおよびパイプラインで実行する

完了

Andy と Amita は、パイプラインでテストを実行する前に、新しい UI テストで必要なことが実行されることを確認したいと考えています。 このセクションでは、最初に Selenium UI テストをローカルで実行し、次にパイプラインで実行して進めます。

自動テストの作成は、他の種類のコードを記述するのと同じように反復的なプロセスです。 独自のアプリの場合は、いくつかの方法を試してみる必要があります。リファレンス ドキュメントとコード例を参照し、ビルド エラーを修正してください。

省略可能: Microsoft Edge 用の Selenium ドライバーをインストールする

テストが Microsoft Edge でローカルに実行されることを確認したい場合は、このセクションに従います。

Chrome および Firefox 用の NuGet パッケージは、コンパイルされたテスト コードと共に、bin ディレクトリの下にドライバー ソフトウェアをインストールします。 Edge の場合は、ドライバーを手動でインストールする必要があります。 そのためには次を行います。

  1. Microsoft Edge をインストールします。

  2. Edge を開いて edge://settings/help に移動します。 バージョン番号をメモしておきます。 次に例を示します。

    A screenshot of the Microsoft Edge setting page, showing the version number.

  3. [Microsoft Edge Driver downloads] ページに移動し、Edge バージョン番号と一致するドライバーをダウンロードします。 次に例を示します。

    A screenshot of the Downloads section of the Microsoft Edge Driver page showing the matching driver version.

  4. プロジェクトの Tailspin.SpaceGame.Web.UITests ディレクトリの下の bin/Release/net6.0 ディレクトリに .zip ファイルを抽出します。 これらのディレクトリが存在しない場合は、作成します。

macOS では、msedgedriver を実行できるようにシステム ポリシーの更新が必要な場合があります。 これを行うには、Visual Studio Code のターミナルから次の spctl コマンドを実行します。

spctl --add Tailspin.SpaceGame.Web.UITests/bin/Release/net6.0/msedgedriver

環境変数をエクスポートする

このモジュールの後の方で、Windows Server 2019 で Selenium テストを実行します。 このドキュメントには、プレインストールされているソフトウェアのリストが示されています。

Selenium Web Drivers」セクションに、Chrome、Firefox、および Edge で使用可能な Selenium ドライバーのバージョンがリストされます。 次に例を示します。

A screenshot showing the documentation for the installed Selenium drivers on the build agent.

ドライバーごとに、そのドライバーの場所にマップされる環境変数があります。 たとえば、ChromeWebDriver は Chrome ドライバーの場所にマップされます。

単体テストのコードは、これらの環境変数を読み取るようにあらかじめ設定されています。 これらの変数では、ドライバーの実行可能ファイルを検索する場所を Selenium に指示します。 単体テストをローカルで実行するには、これらの同じ環境変数をエクスポートする必要があります。

Visual Studio Code から、ターミナルに移動します。 次のコマンドを実行します。 示されているパスは、mslearn-tailspin-space game-web deploy プロジェクトの完全パスに置き換えてください。

重要

必ず、これらのコマンドを実行し、テストの実行に使用するのと同じターミナル ウィンドウで環境変数を設定してください。

driverDir="C:\Users\user\mslearn-tailspin-spacegame-web-deploy\Tailspin.SpaceGame.Web.UITests\bin\Release\net6.0"
export ChromeWebDriver=$driverDir
export EdgeWebDriver=$driverDir
export GeckoWebDriver=$driverDir

ローカルで UI テストを実行する

HomePageTest.csSetup メソッドは、driver メンバー変数を設定した後、Space Game ホーム ページに移動します。

サイトの URL をハードコーディングすることもできますが、ここでは SITE_URL という名前の環境変数から URL を読み取ります。 このようにすると、異なる URL に対して複数回テストを実行できます。

// Navigate to the site.
// The site name is stored in the SITE_URL environment variable to make 
// the tests more flexible.
string url = Environment.GetEnvironmentVariable("SITE_URL");
driver.Navigate().GoToUrl(url + "/");

Space Game Web サイトをまだ App Service 環境にデプロイしていないため、Microsoft がホストするサイトを使用して、テストをローカルで実行します。

ローカルでテストを実行するには、次の手順を実行します。

  1. Visual Studio Code で、統合ターミナルに移動し、新しいターミナル ウィンドウを開きます。

  2. 新しいターミナル ウィンドウで次のコマンドを実行します。

    dotnet build --configuration Release
    dotnet run --configuration Release --no-build --project Tailspin.SpaceGame.Web
    
  3. ローカル Web サイトのリンクをメモしておきます。この例では、http://localhost:5000 です。

  4. 前の手順で環境変数を設定したターミナル ウィンドウに戻り、プロジェクトのルート ディレクトリにいることを確かめます。 次に例を示します。

    cd ~/mslearn-tailspin-spacegame-web-deploy
    
  5. SITE_URL 環境変数をエクスポートします。 前の手順で取得したローカルで実行されているリンクを使用します。

    export SITE_URL="http://localhost:5000"
    

    この変数は、Microsoft がホストする Space Game Web サイトを指します。

  6. UI テストを実行します。

    dotnet test --configuration Release Tailspin.SpaceGame.Web.UITests
    

    このコードでは、Tailspin.SpaceGame.Web.UITests プロジェクトにあるテストを実行します。

    テストの実行中、1 つ以上のブラウザーが表示されます。 Selenium は、各ブラウザーを制御し、定義したテスト ステップに従います。

    Note

    3 つのブラウザーがすべて表示されなくても心配しないでください。 たとえば、Chrome がインストールされていない場合や互換性のないバージョンの場合、Chrome でテストが実行されることはありません。 1 つのブラウザーだけ確認すれば、テストが正常に機能していることを確信できます。 実際には、ローカルの開発環境では、テスト対象のすべてのブラウザーを設定することが必要になる場合があります。 この設定を使用すると、パイプラインでテストを実行する前に、各構成でテストが期待どおりに動作することを確認できます。

  7. ターミナルから、各テストの出力をトレースします。 最後にあるテスト実行の概要にも注意してください。

    この例では、9 つのテストのうち、9 つすべてのテストが成功し、スキップされたテストはないことを示しています。

    Passed!  - Failed:     0, Passed:     9, Skipped:     0, Total:     9, Duration: 5 s 
    

Azure Pipelines に SITE_URL 変数を追加する

前に、SITE_URL 環境変数をローカルに設定して、各ブラウザーを指す場所がテストに認識されるようにしました。 この変数を Azure Pipelines に追加できます。 このプロセスは、App Service インスタンスの変数を追加した方法と似ています。 エージェントを実行すると、この変数は環境変数として自動的にエージェントにエクスポートされます。

パイプラインの構成を更新する前に、ここでパイプラインの変数を追加しましょう。 そのためには次を行います。

  1. Azure DevOps で、Space Game - web - Functional tests プロジェクトにアクセスします。

  2. [パイプライン][ライブラリ] を選択します。

  3. [Release] 変数グループを選択します。

  4. [Variables] で、[+ Add] を選択します。

  5. 変数の名前として「SITE_URL」と入力します。 値として、"テスト" 環境に対応する App Service インスタンスの URL (http://tailspin-space-game-web-test-10529.azurewebsites.net など) を入力します。

  6. ページの上部にある [Save] を選択して、変数をパイプラインに保存します。

    変数グループはこちらのようになるはずです。

    A screenshot of Azure Pipelines, showing the variable group. The group contains four variables.

パイプライン構成を変更する

このセクションでは、"テスト" ステージで Selenium UI テストを実行するようにパイプライン構成を変更します。

  1. Visual Studio Code で、azure-pipelines.yml ファイルを開きます。 その後、次のようにファイルを変更します。

    ヒント

    このファイルにはいくつかの変更が含まれているため、ファイル全体をここに表示される内容に置き換えることをお勧めします。

    trigger:
    - '*'
    
    variables:
      buildConfiguration: 'Release'
      dotnetSdkVersion: '6.x'
    
    stages:
    - stage: 'Build'
      displayName: 'Build the web application'
      jobs: 
      - job: 'Build'
        displayName: 'Build job'
        pool:
          vmImage: 'ubuntu-20.04'
          demands:
          - npm
    
        variables:
          wwwrootDir: 'Tailspin.SpaceGame.Web/wwwroot'
          dotnetSdkVersion: '6.x'
    
        steps:
        - task: UseDotNet@2
          displayName: 'Use .NET SDK $(dotnetSdkVersion)'
          inputs:
            version: '$(dotnetSdkVersion)'
    
        - task: Npm@1
          displayName: 'Run npm install'
          inputs:
            verbose: false
    
        - script: './node_modules/.bin/node-sass $(wwwrootDir) --output $(wwwrootDir)'
          displayName: 'Compile Sass assets'
    
        - task: gulp@1
          displayName: 'Run gulp tasks'
    
        - script: 'echo "$(Build.DefinitionName), $(Build.BuildId), $(Build.BuildNumber)" > buildinfo.txt'
          displayName: 'Write build info'
          workingDirectory: $(wwwrootDir)
    
        - task: DotNetCoreCLI@2
          displayName: 'Restore project dependencies'
          inputs:
            command: 'restore'
            projects: '**/*.csproj'
    
        - task: DotNetCoreCLI@2
          displayName: 'Build the project - $(buildConfiguration)'
          inputs:
            command: 'build'
            arguments: '--no-restore --configuration $(buildConfiguration)'
            projects: '**/*.csproj'
    
        - task: DotNetCoreCLI@2
          displayName: 'Publish the project - $(buildConfiguration)'
          inputs:
            command: 'publish'
            projects: '$(System.DefaultWorkingDirectory)/**/Tailspin.SpaceGame.Web.csproj' 
            publishWebProjects: false
            arguments: '--no-build --configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)/$(buildConfiguration)'
            zipAfterPublish: true
    
        - publish: '$(Build.ArtifactStagingDirectory)'
          artifact: drop
    
    - stage: 'Dev'
      displayName: 'Deploy to the dev environment'
      dependsOn: Build
      jobs:
      - deployment: Deploy
        pool:
          vmImage: 'ubuntu-20.04'
        environment: dev
        variables:
        - group: Release
        strategy:
          runOnce:
            deploy:
              steps:
              - download: current
                artifact: drop
              - task: AzureWebApp@1
                displayName: 'Azure App Service Deploy: website'
                inputs:
                  azureSubscription: 'Resource Manager - Tailspin - Space Game'
                  appName: '$(WebAppNameDev)'
                  package: '$(Pipeline.Workspace)/drop/$(buildConfiguration)/*.zip'
    
    - stage: 'Test'
      displayName: 'Deploy to the test environment'
      dependsOn: Dev
      jobs:
      - deployment: Deploy
        pool:
          vmImage: 'ubuntu-20.04'
        environment: test
        variables:
        - group: 'Release'
        strategy:
          runOnce:
            deploy:
              steps:
              - download: current
                artifact: drop
              - task: AzureWebApp@1
                displayName: 'Azure App Service Deploy: website'
                inputs:
                  azureSubscription: 'Resource Manager - Tailspin - Space Game'
                  appName: '$(WebAppNameTest)'
                  package: '$(Pipeline.Workspace)/drop/$(buildConfiguration)/*.zip'
      - job: RunUITests
        dependsOn: Deploy
        displayName: 'Run UI tests'
        pool:
          vmImage: 'windows-2019'
        variables:
        - group: 'Release'
        steps: 
        - task: UseDotNet@2
          displayName: 'Use .NET SDK $(dotnetSdkVersion)'
          inputs:
            version: '$(dotnetSdkVersion)'
        - task: DotNetCoreCLI@2
          displayName: 'Build the project - $(buildConfiguration)'
          inputs:
            command: 'build'
            arguments: '--configuration $(buildConfiguration)'
            projects: '$(System.DefaultWorkingDirectory)/**/*UITests.csproj'
        - task: DotNetCoreCLI@2
          displayName: 'Run unit tests - $(buildConfiguration)'
          inputs:
            command: 'test'
            arguments: '--no-build --configuration $(buildConfiguration)'
            publishTestResults: true
            projects: '$(System.DefaultWorkingDirectory)/**/*UITests.csproj'
    
    - stage: 'Staging'
      displayName: 'Deploy to the staging environment'
      dependsOn: Test
      jobs:
      - deployment: Deploy
        pool:
          vmImage: 'ubuntu-20.04'
        environment: staging
        variables:
        - group: 'Release'
        strategy:
          runOnce:
            deploy:
              steps:
              - download: current
                artifact: drop
              - task: AzureWebApp@1
                displayName: 'Azure App Service Deploy: website'
                inputs:
                  azureSubscription: 'Resource Manager - Tailspin - Space Game'
                  appName: '$(WebAppNameStaging)'
                  package: '$(Pipeline.Workspace)/drop/$(buildConfiguration)/*.zip'
    

    このファイルには、次の 3 つの変更が含まれています。

    • dotnetSdkVersion 変数は、複数のステージでアクセスできるように、ファイルの先頭に移動されています。 ここでは、"ビルド" ステージと "テスト "ステージにこのバージョンの .NET Core が必要です。

    • "ビルド" ステージでは、ビルド成果物として Space Game Web サイト パッケージのみが発行されます。 以前は、次のような成果物を発行しました。

      - task: DotNetCoreCLI@2
        displayName: 'Publish the project - $(buildConfiguration)'
        inputs:
          command: 'publish'
          projects: '**/*.csproj'
          publishWebProjects: false
          arguments: '--no-build --configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)/$(buildConfiguration)'
          zipAfterPublish: true
      

      このタスクは 2 つのビルド成果物 (Space Game Web サイト パッケージとコンパイル済み UI テスト) を生成します。 "ビルド" ステージで UI テストをビルドして、"テスト" ステージで確実にコンパイルされるようにしますが、コンパイルされたテスト コードを発行する必要はありません。 テストの実行時に、"テスト" ステージでもう一度ビルドします。

    • "テスト" ステージには、テストをビルドして実行する 2 つ目のジョブが含まれています。 このジョブは、「Azure Pipelines を使用してビルド パイプラインで品質テストを実行する」モジュールで使用したものに似ています。 そのモジュールでは、ランキングのフィルター処理機能を確認する NUnit テストを実行しました。

      "デプロイ ジョブ" は、デプロイ ステージで重要な役割を果たす特別な種類のジョブであることを思い出してください。 2 番目のジョブは、Windows Server 2019 エージェントで Selenium テストを実行する通常のジョブです。 Linux エージェントを使用してアプリケーションをビルドしますが、ここでは Windows エージェントを使用して UI テストを実行します。 Amita は Windows で手動テストを実行するため、Windows エージェントを使用します。これは、ほとんどのお客様が使用しているものです。

      RunUITests ジョブは Deploy ジョブに依存して、ジョブが正しい順序で実行されるようにします。 UI テストを実行する前に、App Service に Web サイトをデプロイします。 この依存関係を指定しない場合は、ステージ内のジョブを任意の順序で実行することも、並列で実行することもできます。

  2. 統合ターミナルで、azure-pipelines.yml をインデックスに追加し、変更をコミットして、GitHub にブランチをプッシュします。

    git add azure-pipelines.yml
    git commit -m "Run Selenium UI tests"
    git push origin selenium
    

Azure Pipelines でのテストの実行を監視する

ここでは、パイプラインの実行を監視します。 パイプラインは、"テスト" ステージで Selenium UI テストを実行します。

  1. Azure Pipelines で、ビルドに移動し、実行中にそれをトレースします。

    ビルド中、Web サイトのデプロイ後に自動テストが実行されます。

    A screenshot of Azure Pipelines, showing the running stages.

  2. ビルドが完了したら、概要ページに移動します。

    A screenshot of Azure Pipelines, showing the completed stages.

    デプロイと UI テストが正常に完了したことがわかります。

  3. ページの上部近くにある概要を確認します。

    Space Game Web サイトのビルド成果物が、いつものように発行されていることがわかります。 また、Selenium テストが成功したことを示している [Tests and coverage] セクションにも注意してください。

    A screenshot of Azure Pipelines, showing the test summary.

  4. テストの概要を選択して、完全なレポートを表示します。

    このレポートには、9 つのテストがすべて成功したことが示されます。 これらのテストには、3 つのブラウザーにまたがる 3 つのテストが含まれます。

    A screenshot of Azure Pipelines, showing the full test report.

    テストが失敗した場合は、失敗の詳細な結果が表示されます。 そこから、エラーの原因を調査してローカルで修正してから、必要な変更をプッシュして、パイプラインでテストを成功させることができます。

Amita: この自動化は魅力的です! これで、パイプラインで実行できる UI テストができました。 このテストにより、間違いなく長期的に時間が節約されます。 また、さらにテストを追加するために従うべきパターンもあります。 何よりも、UI テストにより、コード品質に対する信頼が高まります。

Andy: まったくそのとおりです。 手動で繰り返し実行するテストは、自動化の候補として適していることを忘れないでください。 さらに追加することをお勧めします。 行き詰まった場合や、コード レビュー担当者が必要な場合は、いつでも連絡してください。