Posted at

Xamarin.iOS 単体テストを Visual Studio Team Services 上で動作させる方法

More than 1 year has passed since last update.


はじめに

この資料は、Xamarin.iOS の Unit Test を VSTS 上で実行する手順について記載します。



  • Xamarin Blog の記事をベースに検証を行いました


    • Blog 記事をそのまま検証するだけでなく、工夫を加えている箇所があります



  • Simulator 上で単体テストを実施しています


サンプルコード

検証に利用したソースコードを、GitHub に公開しています。

今回の検証では、iOS のクラスライブラリを単体テストする場合を考えます。

プロジェクト名
説明

XamarinUnitTestsVsts.iOS.Service
単体テスト対象のプロジェクト。サンプルでは、Calculator クラスの単体テストを行っています

XamarinUnitTestsVsts.iOS.Service.Test
単体テストプロジェクト。サンプルでは、意図的にテストを失敗させています


手順

具体的な手順を記載します。


Touch.Server.exe をダウンロードする

Touch.Server.exe は、Xamarin.iOS 単体テストをサポートするツールで、このツールを利用して単体テストを実行すると、テスト結果のレポートファイルを容易に取り出すことができます。

このツールをダウンロードし、テストプロジェクトのディレクトリに配置します。


  • 配置するディレクトリは自由です


    • 配置したディレクトリに合わせて、後述する Shell スクリプトを書き換えてください



  • VSTS 上で Touch.Server.exe を起動するため、ソースコードのリポジトリにコミットするようにしてください


1. Unit Test プロジェクトの設定

ビルド時に以下の環境変数を設定するように、ビルドの設定を修正します。具体的には、プロジェクトの iOS Build の設定に以下の設定を追加します。

環境変数名

NUNIT_ENABLE_XML_OUTPUT
true

NUNIT_SKIP_LOG_HEADER
true

今回は、VSTS 上で Simulator を動作させるため、ビルドの構成は、'Debug','iPhoneSimulator' で、設定を追加しています。


2. Touch.Server を起動する Shell スクリプトを作成する

Touch.Server.exe を起動するための Shell スクリプトを作成します。

#!/bin/sh

echo 'Output path = ' $1
TEST_RESULT=$1/test_results.xml
echo 'Delete test result'
rm -rf $TEST_RESULT
mono --debug $1/Touch.Server.exe \
--launchsim ./bin/iPhoneSimulator/Debug/XamarinUnitTestsVsts.iOS.Service.Test.app \
-autoexit \
-skipheader \
-logfile=$TEST_RESULT \
--verbose \
--device=":v2:runtime=com.apple.CoreSimulator.SimRuntime.iOS-11-3,devicetype=com.apple.CoreSimulator.SimDeviceType.iPhone-8"

ビルドサーバーの環境によって、--device のオプションの値を適宜修正する必要があります。

検証を行った環境では、iOS 11.3 の iPhone 8 の Simulator を利用しています。


3. Visual Studio Team Services のビルド設定

ここでは、VSTS 上のビルドタスクに関する説明を記載します。


0. ビルドの流れ

VSTS で Xamarin.iOS のビルドタスクを作成し、単体テストを実行するために必要なビルドタスクを追加します。今回の検証では、以下の図の (1) ~ (6) のタスクを追加しています。

#
VSTS タスク
概要

1
MSBuild
単体テストプロジェクトをビルドするタスクです

2
Shell Script
Touch.Server.exe を起動し、単体テストを実行するための Shell スクリプトを実行するタスクです

3
Publish Test Results
テストレポートのファイルを VSTS に登録するタスクです

4
Set variable with value from XML
テストレポートファイルから、エラー件数を取得し、VSTS の変数にその値を格納するタスクです

5
Set variable with value from XML
テストレポートファイルから、失敗の件数を取得し、VSTS の変数にその値を格納するタスクです

6
Command Line
テストレポートに、エラー、失敗があった場合にビルドを失敗させるためのタスクです

#4 ~ #6 のタスクが、参考にした Xamarin Blog に工夫を加えた点です。実は、VSTS の "Publish Test Reslts" タスクは、失敗したテストケース結果が含まれるレポートを登録しても、ビルドタスクを成功扱いにしてしまいます。参考にした記事ではこの点については、GitHub で議論されている最中だと述べるにとどめています。

そこで、本記事では、以下に記載する方法で、テストレポートにテストケースの失敗やエラーがあれば、ビルドが失敗扱いとなるようにビルドタスクを組み込んでいます。


  • 単体テスト完了後、テストレポートファイルを解析する

  • テストレポートにエラーが含まれていたら、ビルドタスクを失敗させる


テストレポートファイルの解析

テストレポートを解析する方法には、いろいろな方法が考えられます。テストレポートのファイルは、XML ファイルであり、test-results 要素の属性にテストの成功、失敗などの件数が格納されていますので、この値を VSTS のビルドタスクで取得する方法を考えます。

<?xml version="1.0" encoding="utf-8" standalone="no"?>

<!--This file represents the results of running a test suite-->
<test-results
name=""
total="5"
errors="0"
failures="2"
not-run="1"
inconclusive="0"
ignored="1"
skipped="0"
invalid="0"
date="2018-04-19" time="08:28:42">
... 省略
</test-results>

今回の検証では、VSTS の拡張機能(Variables Tasks Pack)を利用して、test-results 要素の errors, failures 属性の値を取得し、VSTS の変数に格納し、後述の Command Line タスクでテストの成功・失敗の判定に利用しています。


Command Line タスク

VSTS で提供される Command Line タスクは、標準エラーに出力を行った場合には、タスクをエラー扱いとすることができます。

Command Line タスクの Script で、echo Failed 1>&2 のように標準ラー出力を行い、'Advanced' の設定で 'Faile on Standard Error' にチェックを入れることで標準エラーに何らかの出力を行うとタスクをエラーとすることができます。

テストレポートにエラーが含まれるという条件判定には、VSTS の Control Option の Custom condition を利用します。

標準エラー出力を行って、ビルドタスクを失敗される方法は、以下のサイトを参考にしました。


1. ビルドタスク

MSBuild タスクを利用して、ユニットテスト対象のプロジェクトをビルドします。ビルド対象のプロジェクトに単体テストプロジェクトを指定します。



  • Project


    • 単体テストプロジェクトのプロジェクトファイルを指定します




2. Shell Scrpt を実行する

Shell Script タスクを利用して、Touch.Server.exe を起動する Shell スクリプトを実行します。



  • Script Path


    • Touch.Server.exe を起動する Shell Script ファイルを指定します




  • Arguments


    • 単体テストのルートパスを指定します




3. テストレポートの登録

Publish Test Results タスクを利用して、テストレポートを VSTS に登録します。



  • Test results files


    • テストレポートのファイルを指定します




  • Search folder


    • テストレポートが出力されるフォルダを指定します


      • レポートの出力フォルダは、Touch.Server.exe を起動する Shell スクリプトを参照してください






4. エラー件数の値の取得と VSTS 変数への格納

Set variable with value from XML ビルドタスク(拡張機能)を利用して、レポートファイルを解析し、エラーの件数を VSTS の変数に格納します。



  • Variable Name


    • 取得した値を格納する変数名を指定します


      • 今回の検証では、NUnitTestResult.Erros という名前の変数に値を格納しています






  • XPath expression


    • 取得したい XML の要素(属性)を XPath 形式で記述します。ここでは、 errors 属性の値を取得しています




  • XML file path


    • 単体テストレポート XML ファイルをフルパスで指定します




5. 失敗した件数の値の取得と VSTS 変数への格納

Set variable with value from XML ビルドタスク(拡張機能)を利用して、レポートファイルを解析し、テスト失敗の件数を VSTS の変数に格納します。



  • Variable Name


    • 取得した値を格納する変数名を指定します


      • 今回の検証では、NUnitTestResult.Failures という名前の変数に値を格納しています






  • XPath expression


    • 取得したい XML の要素(属性)を XPath 形式で記述します。ここでは、 failures 属性の値を取得しています




  • XML file path


    • 単体テストレポート XML ファイルをフルパスで指定します




6. テストレポートにエラーが含まれていた場合に、ビルドを失敗にする

Command Line タスクを利用して、単体テストのレポートにエラー・失敗が含まれていた場合は、ビルドタスクを失敗させます。



  • Script


    • 標準エラーにメッセージを出力します




  • Advanced の設定で Fail on Standard Error にチェックを入れます



  • Control Options



    • Run this taskCustom conditions を選択します


    • Custom Condition で以下の条件を入力します


      • 以下のいずれかの場合にタスクが失敗します


        • すでにビルドが失敗している場合


        • NUnitTestResult.Erros 変数の値が 0 でない場合


        • NUnitTestResult.Failures 変数の値が 0 でない場合







or(failed(), ne(variables['NUnitTestResult.Erros'], '0'), ne(variables['NUnitTestResult.Failures'], '0'))

VSTS の Custom condition に関する詳細は、以下を参照してください。


実行

VSTS 上でビルドタスクを実行すると、単体テストが実行され、テスト結果のレポートが登録されることがわかります。


おわりに

Touch.Server.exe を利用することで、iOS の単体テストプロジェクトを自動ビルドプロセスの中に組み込むことができるようになることが確認できました。

Android の場合はどうなるのかと思う方がいるかもしれませんが、Android 向けに Touch Server For Android というツールが GitHub で公開されています。このツールを利用した VSTS 上での単体テストの実行方法については、後日検証してみたいと考えています。


参考