Xamarin.UITestのススメ

4 min read読了の目安(約4100字

Xamarin.UITestとは

NUnitテストフレームワークを使用してC#で記述された自動UIテストをiOSおよびAndroidアプリケーションに対して実行できるようにするテストフレームワークです。

Xamarin.iOSおよびXamarin.Androidプロジェクトと緊密に統合されていますが、Objective-C / SwiftおよびJavaでネイティブに記述されたiOSおよびAndroidプロジェクトでも使用できます。

実際にXamarin.formsで作成したアプリに対して試してみましょう。

用意するもの

  • Windows 10 (Home、Proどちらでも)
  • Visual Studio 2019 (Version 16.7.5)

前提条件

  • Visual Studio を使ってXamarin.Formsでの開発ができる環境がある。
  • Androidエミュレーターを使ってデバッグができる。
  • UITestするためのXamarin.formsのプロジェクトがある。

Xamarin.UITestプロジェクトの作成

新しいプロジェクトを作成 → Xamarin.UITest クロスプラットフォームのテストプロジェクトを選択

「SampleUITest」という名前で作成すると以下のようなプロジェクトが作成されます。

Windowsの場合、システムの詳細設定で環境変数に

変数:ANDROID_HOME
値:C:\Program Files (x86)\Android\android-sdk

Pathに

%ANDROID_HOME%\tools

%ANDROID_HOME%\platform-tools

を追加する必要があります。

テスト対象の設定

今回はAndroidエミュレータでUITestを試すので、それ用に設定を変えていきます。
まずは、AppInitializer.csを編集します。

 using System;
 using Xamarin.UITest;
 using Xamarin.UITest.Queries;
 
 namespace SampleUITest
 {
     public class AppInitializer
     {
         public static IApp StartApp(Platform platform)
         {
             if (platform == Platform.Android)
             {
                 return ConfigureApp
                           .Android
                           .ApkFile("ここにAPKファイルのパス")
                           .StartApp();
             }
 
             return ConfigureApp.iOS.StartApp();
         }
     }
 }

IAppインターフェースを継承するAndroid、iOSオブジェクトはアプリへの操作を提供してくれます。

AppInitializer.csでは、選択したPlatformに応じてAndroidかiOSオブジェクトを生成するクラスです。

上記の.ApkFile("")には、Releaseビルドで生成されたAPKファイルへのパスを記載します。

テストの記述

まず、テスト対象のアプリ側には以下のような入力欄を用意しておきます。

 <Entry AutomationId="TestEntry" 
        ClearButtonVisibility="WhileEditing" 
        HorizontalOptions="FillAndExpand" 
        VerticalOptions="CenterAndExpand"/>

ここに対して自動で値が入力されるのを確認します。

Xamarin.UITestでは「AutomationId」という一意の識別子を設定することで画面上の要素を特定し操作ができます。

上記のソースでは「AutomationId="TestEntry"」と設定しています。

ではテストを書いて実行してみましょう。

Tests.csに以下のテストコードを記述します。

 [Test]
 public void EntryTest()
 {
      app.EnterText(c => c.Marked("TestEntry"), "UITest");
      app.PressEnter();
      Assert.AreEqual("UITest", app.Query(c => c.Marked("TestEntry"))
      .FirstOrDefault().Text);
 }

.EnterText()はEntryに対して指定した文字列を入力してくれるメソッドです。

実際にテストを流してみると、テストは成功し、エミュレーターでは以下のようにEntryに文字が入力されると思います。

またAutomationId以外にも、Xamarin.UITestはいろいろな要素の指定方法があります。

一例としてClass指定でビューを指定する方法を紹介します。

先ほどのソースコードを以下のように変更します。

 [Test]
  public void EntryTest()
  {
        app.EnterText(c => c.Class("EntryRenderer").Index(0), "UITest");
        app.PressEnter();
        Assert.AreEqual("UITest", app.Query(c => c.Marked("TestEntry"))
	.FirstOrDefault().Text);
  }

Class指定で取得すると、要素が一つでない時があるので、上記の「Index(0)」のように何番目の要素か指定する必要があります。

Xamarin.UITestには、画面上の要素の階層構造を知る方法があります。

先ほどのソースコードを以下のように変更します。

 [Test]
  public void EntryTest()
  {
        app.EnterText(c => c.Class("EntryRenderer").Index(0), "UITest");
        app.PressEnter();
        app.Repl();
        Assert.AreEqual("UITest", app.Query(c => c.Marked("TestEntry"))
	.FirstOrDefault().Text);
  }

これで実行すると、app.Repl()で以下のようにコマンドプロンプトが開きます。

そこで、「tree」と入力しEnterを押します。

すると以下のように階層構造を見ることができます。

[]で囲まれているのがClass名です。そのほかにもいろいろな情報をここで見ることができますね。

ちなみにapp.Print.Tree()でこの階層構造をConsole出力することもできます。

いかがだったでしょうか。

Xamarin.formsでアプリを作成しているなら、導入してみてもいいかもしれません。

それでは良い自動テストライフを!

最後に私が実際に困ったときの事例を紹介して終わります

Tips

  • SearchBarに入力したいとき

Class指定で「SearchView」を指定

 app.EnterText(c => c.Class("SearchView"), "Test");
  • DatePickerに入力したいとき

Invokeでネイティブのメソッドを呼び出す

 var date = new DateTime(2020, 10, 30);
 app.Query(c => c.Class("DatePicker")
    .Invoke("updateDate", date.Year, date.Month, date.Day));