Shiratesを使ってみよう - セレクター式 -
セレクター式
Shiratesのセレクター式は画面要素をフィルターするための式です。 select関数はセレクター式を引数にとり、解析を行い、画面要素を取り出してフィルターし、結果として取得された要素を返します。 セレクター式は1つ以上のフィルター式から成ります。
フィルター式
フィルター | フォーマルな書式 | 省略形 | Androidの属性 | iOSの属性 |
---|---|---|---|---|
text | text=text1 | text1 | text | label |
textStartsWith | textStartsWith=text1 | text1* | text | label |
textContains | textContains=text1 | *text1* | text | label |
textEndsWith | textEndsWith=text1 | *text1 | text | label |
textMatches | textMatches=^text$ | n/a | text | label |
literal | literal=literal1 | 'literal1' | text | label |
id | id=id1 | #id1 | resource-id | name |
access | access=access1 | @access1 | content-desc | name |
accessStartsWith | accessStartsWith=access1 | @access1* | content-desc | name |
accessContains | accessContains=access1 | @*access1* | content-desc | name |
accessEndsWith | accessEndsWith=access1 | @*access1 | content-desc | name |
accessMatches | accessMatches=^access1$ | n/a | content-desc | name |
value | value=value1 | n/a | text | value |
valueStartsWith | valueStartsWith=value1 | n/a | text | value |
valueContains | valueContains=value1 | n/a | text | value |
valueEndsWith | valueEndsWith=value1 | n/a | text | value |
valueMatches | valueMatches=^value1$ | n/a | text | value |
class | class=class1 | .class1 | class | type |
focusable | focusable=true | n/a | focusable | n/a |
scrollable | scrollable=true | n/a | scrollable | n/a |
visible | visible=true | n/a | n/a | visible |
xpath | xpath=//*[@text='text1'] | n/a | (arbitrary) | (arbitrary) |
pos | pos=2 | [2] | n/a | n/a |
ignoreTypes | ignoreTypes=Class1,Class2 | n/a | class | type |
image | image=image1.png | image1.png | n/a | n/a |
フィルターにおける複数値の指定
フィルターは複数の値を (value1|value2)
のように丸括弧と"|"(or)演算子で受け取ることができます。
it.select("text=(text1|text2)") // フォーマルな書式 it.select("(text1|text2)") // 省略形の書式
以下のセレクター式はシンプルですが上記と等価です。
it.select("text1||text2") // 等価なセレクター式
もっと複雑な状況では"|"が必要になるかもしれません。
it.select("(text1|text2)&&.class1||(@access1|@access2)&&.class2)")
セレクター式の規則
フィルター式は単独でセレクター式として使用できます。
text1
フィルター式は"&&"(AND)演算子で結合することができます。
text1&&.class1&&visible=true
フィルター式は"||"(OR)演算子で結合することができます。
text1||text2||@access1
"&&"は"||"よりも優先されます。
text1&&.class1||@access1
上記は(text=text1 and class=class1) or access=access1
の意味となります。
ただし、以下のように丸括弧を使用することはできません(サポートしていません)。
悪い例
(text1&&.class1)||@access1
完全修飾ID
Androidのresource-id
はパッケージ名に対応したプレフィックスを持っています。例えば設定アプリは"com.android.settings
がパッケージ名です。
完全修飾形 | 省略形 |
---|---|
com.android.settings:id/search_bar | search_bar |
Shiratesでは完全修飾形への自動変換が行われ、かつ可読性が高いことから省略形の使用が推奨されます。 自動変換ではうまくいかない場合は完全修飾形を使用します。
セレクター式のためのプラットフォームアノテーション
プラットフォームアノテーション(@a, @i)を使用するとAndroid用とiOS用のセレクター式を1行で記述することができます。
@a<.android.widget.ImageButton>,@i<.XCUIElementTypeButton>
it.select("@a<.android.widget.ImageButton>,@i<.XCUIElementTypeButton>")
この記述を使用してニックネームを定義することができます。
"[Button1]": "@a<.android.widget.ImageButton>,@i<.XCUIElementTypeButton>"
否定フィルター
複雑な状況においては否定フィルターを使用することができます。
text=text1 // 通常のフィルター text!=text1 // 否定フィルター text1 // 通常のフィルター !text1 // 否定フィルター accessContains=text1 // 通常のフィルター accessContains!=text1 // 否定フィルター @*text1* // 通常のフィルター !@*text1* // 否定フィルター
画像フィルター
画像ファイルを使用して画像マッチング(テンプレートマッチング)を行うことができます。 画像による検証
image=image1.png // フォーマルな形式 image1.png // 省略形 image1.png?scale=0.5&threshold=20 // オプションあり(フォーマルな形式) image1.png?s=0.5&t=20 // オプションあり(省略形)
サンプルコード
サンプルコードの入手
本記事で説明するサンプルコードの完成版はこちらから入手してください。 https://github.com/wave1008/shirates-samples-selectors
SelectorTest2
import org.junit.jupiter.api.Order import org.junit.jupiter.api.Test import shirates.core.driver.branchextension.emulator import shirates.core.driver.branchextension.realDevice import shirates.core.driver.commandextension.* import shirates.core.testcode.UITest class SelectTest2 : UITest() { @Test @Order(10) fun selectByText() { scenario { case(1) { condition { it.restartApp() }.action { it.select("ネットワークとインターネット") }.expectation { it.textIs("ネットワークとインターネット") } } case(2) { action { it.select("ネットワークと*") }.expectation { it.textIs("ネットワークとインターネット") } } case(3) { action { it.select("*とインターネット") }.expectation { it.textIs("ネットワークとインターネット") } } case(4) { action { it.select("textMatches=^ネットワークとインターネット$") }.expectation { it.textIs("ネットワークとインターネット") } } case(5) { action { it.selectWithScrollDown("デバイス情報||エミュレートされたデバイスについて") }.expectation { realDevice { it.textIs("デバイス情報") }.emulator { it.textIs("エミュレートされたデバイスについて") } } } } } @Test @Order(20) fun selectById() { scenario { case(1) { condition { it.restartApp() }.action { it.select("#search_action_bar_title") }.expectation { it.textIs("設定を検索") } } } } @Test @Order(30) fun selectByAccessibility() { scenario { case(1) { condition { it.restartApp() .tap("ネットワークとインターネット") }.action { it.select("@ネットワークとインターネット") }.expectation { it.idIs("collapsing_toolbar") } } } } @Test @Order(40) fun selectByClass() { scenario { case(1) { condition { it.restartApp() }.action { it.select(".android.widget.ImageButton") }.expectation { it.classIs("android.widget.ImageButton") } } } } @Test @Order(50) fun selectByXpath() { scenario { case(1) { condition { it.restartApp() }.action { it.select("xpath=//*[@text='設定を検索']") }.expectation { it.textIs("設定を検索") } } } } @Test @Order(60) fun selectByPos() { scenario { case(1) { condition { it.restartApp() .tap("バッテリー") }.action { it.select("*バッテリー*&&[1]") }.expectation { it.textIs("バッテリー使用量") } } case(2) { action { it.select("*バッテリー*&&[2]") }.expectation { it.textIs("バッテリーセーバー") } } case(3) { action { it.select("*バッテリー*&&[3]") }.expectation { it.textIs("バッテリーを長持ちさせ、充電を最適化します") } } } } }
サンプルコードの実行結果
Shiratesを使ってみよう - select関数 -
Shiratesのselect関数
を紹介します。
画面要素の取得方法
Shiratesでは画面要素を取得するのにAppiumと同様に以下の方法を使用できます。
- text
- content-desc
- resource-id
- class
- xpath
テキスト属性(text)による画面要素の取得
Shiratesでは下記のようにAppiumよりも簡素な記述で要素を取得できます。
select("テキスト")
また、スクロールする画面においては以下のように記述することができます。
selectWithScrollDown("テキスト")
アクセシビリティ属性(content-desc)による画面要素の取得
content-descを指定して要素を取得する場合は"@"を付与します。
select("@上へ移動")
select関数の詳細はこちらを参照ください。
サンプルコード
サンプルコードの入手
本記事で説明するサンプルコードの完成版はこちらから入手してください。 https://github.com/wave1008/shirates-samples-selectors
SelectorTest
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Order import org.junit.jupiter.api.Test import shirates.core.driver.commandextension.* import shirates.core.testcode.UITest class SelectTest : UITest() { @Test @Order(10) @DisplayName("テキスト属性で要素を取得する") fun selectByText() { scenario { case(1) { action { it.select("ネットワークとインターネット") }.expectation { it.textIs("ネットワークとインターネット") } } case(2) { action { it.selectWithScrollDown("システム") }.expectation { it.textIs("システム") } } } } @Test @Order(20) @DisplayName("アクセシビリティ属性(content-desc)で要素を取得する") fun selectByAccessibility() { scenario { case(1) { condition { it.tapWithScrollDown("システム") }.action { it.select("@上へ移動") }.expectation { it.accessIs("上へ移動") } } } } }
サンプルコードの実行結果
Shiratesクイックスタート
本記事は github.com の日本語訳です。
ソフトウェアのインストール
前提となる以下のツールをインストールします。
注意事項
ツールが正常に動作しない場合があるので、以下の文字を含むOSのアカウント名は使用しないでください。
- ASCII文字以外の文字を含む (例:テスト太郎)
- 空白文字を含む (例:test taro )
IntelliJ IDEA
インストールしていない場合はダウンロードしてインストールしてください。Ultimateは有償製品、Communityはオープンソース製品です。 https://www.jetbrains.com/idea/
Android Studio
インストールしていない場合はダウンロードしてインストールしてください。 https://developer.android.com/studio
Xcode(macのみ)
インストールしていない場合はApp Storeで検索してインストールしてください。
Command Line Tools for Xcode(macのみ)
インストールしていない場合はターミナルを開いて以下のコマンドを実行してください。
xcode-select --install
Homebrew(macのみ)
インストールしていない場合は https://brew.sh/ を参照してインストールしてください。
Node Package Manager (NPM)
インストールしていない場合はインストールしてください。 すでにインストールしている場合、バージョンが古いとAppiumが正常に動作しない場合があるので、比較的新しいバージョンにアップグレードしてください。
macの場合
Homebrewを使用してインストールできます。ターミナルを開いて以下のコマンドを実行してください。 (新規インストールの場合)
brew install node node -v
(アップグレードの場合)
brew update brew upgrade node
Windowsの場合
インストールパッケージを入手してインストールしてください。
https://nodejs.org/en/download/
注意事項
インストールしたバージョンが古い場合はAppiumが正常に動作しない場合があるので、比較的新しいバージョンをインストールしてください。
Appium 2.0
インストールしていない場合はインストールしてください。
すでに利用中の場合はバージョンをチェックしてください。
appium -v
Appium 1.xがインストールされている場合はアンインストールしてください。
npm uninstall -g appium
Appium 2.0をnpmでインストールしてください。
npm install -g appium@next appium -v
補足
- Appium 2.0はリリース準備中です。2.0をインストールするには"@next"を指定する必要があります。
- テスト済みの環境を参考にしてください
実行例
appium -v npm uninstall -g appium npm install -g appium@next appium -v
実行結果
wave1008@SNB-M1 ~ % appium -v 2.0.0-beta.33 wave1008@SNB-M1 ~ % npm uninstall -g appium removed 437 packages, and audited 1 package in 816ms found 0 vulnerabilities wave1008@SNB-M1 ~ % npm install -g appium@next added 426 packages, and audited 427 packages in 16s 62 packages are looking for funding run `npm fund` for details found 0 vulnerabilities wave1008@SNB-M1 ~ % appium -v 2.0.0-beta.35 wave1008@SNB-M1 ~ %
UIAutomator2 driver
インストールしていない場合はインストールしてください。
appium driver install uiautomator2@2.7.1
すでにインストールしている場合は再インストールしてください。
appium driver list appium driver uninstall uiautomator2 appium driver install uiautomator2@2.7.1 appium driver list
テスト済みの環境を参考にしてください
XCUITest driver(macのみ)
インストールしていない場合はインストールしてください。
appium driver install xcuitest@4.12.0
すでにインストールしている場合は再インストールしてください。
appium driver list appium driver uninstall xcuitest appium driver install xcuitest@4.12.0 appium driver list
テスト済みの環境を参考にしてください
環境変数(macの場合)
初期化スクリプト(.zshrcなど)で環境変数を設定してください。
設定例
export ANDROID_SDK_ROOT=/Users/$USER/Library/Android/sdk export PATH=$ANDROID_SDK_ROOT/tools:$ANDROID_SDK_ROOT/platform-tools:$PATH
設定変更を有効にするにはログオフしてからログオンし直してください。
環境変数(Windowsの場合)
- Android Studioを開きます。
- メニューから Tools > SDK Manager > Appearance & Behavior > System Settings > Android SDKを選択します。
- Android SDK Locationの値をコピーします。
- システム環境変数に ANDROID_SDK_ROOT を設定します。上記でコピーした値を設定します。
- システム環境変数Pathを編集し、以下のパスを設定します。
%ANDROID_SDK_ROOT%\platform-tools %ANDROID_SDK_ROOT%\tools
6. PCを再起動します。
AVD(Android Virtual Device)のセットアップ
デモ用のAVDを作成する
- Android Studioを開きます。
- メニューから
Tools > Device Manager
を選択します。 Create Device
をクリックします。Pixel 3a
を選択し、Next
をクリックします。S/API Level 31/Android 12.0 (Google Play)
を選択し、Next
をクリックします (電卓アプリをデモで使用するのでGoogle Play Storeが必要となります)。 なお、M1 Macの場合は arm64を、それ以外の場合はx86_64を選択します。- AVDの名前を
Pixel 3a API 31(Android 12)
に設定してFinish
をクリックします。
デモンストレーション
デモを実行しましょう
言語設定
shirates-coreに付随しているデモを実行する際はAndroid OSの言語をEnglish(United States)
に設定してください。
shirates-coreプロジェクトを開く
右クリックでのテスト実行を有効にする
- IntelliJ IDEA > Preferences (または File > Settings)を選択します。
- Build, Execution, Deployment > Build Tools > Gradleを選択します。
- Build and run tests usingを IntelliJ IDEAに設定します。
- Run tests usingをIntelliJ IDEAに設定します。
AndroidSettingsDemoを実行する
- Device Managerから
Pixel 3a API 31(Android 12)
のAVDを起動します。 - IntelliJでshirates-coreプロジェクトを開き、
src/test/Kotlin/demo/AndroidSettingsDemo
を右クリックしてDebug
を選択します。
3.以下のようなログがIntelliJ IDEAのコンソールに出力されます。
出力されたレポートを確認する
- IntelliJ IDEAのコンソールに出力されたログのハイパーリンクをクリックしてログのディレクトリを表示します。
- ログとレポートファイルが出力されていることが確認できます。
- _Report(simple).htmlを開きます。テストの実行結果をHTMLで確認できます。行をクリックすると対応するスクリーンショット画像がハイライトされます。行をダブルクリックするとイメージが拡大表示されます。
- _Report(detail).htmlを開きます。ログタイプがinfoの情報が追加で出力されていることが確認できます。
- AndroidSettingsDemo@a.xlsxを開きます。テストの実行結果を表形式で確認できます。
- TestList_androidSettingsConfig.xlsxを開きます。一覧でテスト結果を確認できます。
CalculatorDemoを実行する
- Device Managerから
Pixel 3a API 31(Android 12)
のAVDを起動します。 - Google Play Storeを開き、
Calculator(Google LLC)
をインストールします。 - IntelliJでshirates-coreプロジェクトを開き、
src/test/Kotlin/demo/CalculatorDemo
を右クリックしてDebug
を選択します。 - 電卓のテストが実行されることを確認します。
iOSSettingsDemoを実行する
wave1008/shirates-samples-practice1
QiitaにポストしたShiratesの紹介記事です。 qiita.com
この記事で使用しているPractice1のサンプルをGitHubにアップしました。 github.com
git cloneしてお試しください。
git clone https://github.com/wave1008/shirates-samples-practice1.git
Introducing Shirates, a Mobile Testing Automation Tool
DEVに記事をポストしました。
Shiratesを使ってみよう - testrunファイル -
前回の記事ではShiratesの環境構築と簡単なテストコードの作成を説明しました。 wave-diary.hatenablog.com
本記事で説明する内容を手元で実行する場合は先に前回の記事に従ってプロジェクトを作成してください。 または完成したプロジェクトをこちらから入手してください。
Shiratesのパラメーター設定
Shiratesは パラメーター構成ファイル で起動パラメーターを設定できます。
testrun.propertiesファイル
testrun.propertiesファイルを編集して以下の内容に書き換えます。
#testrun ## OS -------------------- #os=ios ## Config -------------------- ## [Android] android.configFile=testConfig/settingsConfig.json android.profile=Android 12 ## [iOS] #ios.configFile= #ios.profile= ## Stub -------------------- #stubServerUrl=http://stub1 ## Test mode -------------------- #noLoadRun=true ## Priority filter -------------------- #must=false #should=false #want=false #none=false ## Log -------------------- logLanguage=ja #enableSyncLog=false #enableTestList=false #enableSpecReport=false #enableInnerMacroLog=true #enableInnerCommandLog=true #enableSilentLog=true #enableTapElementImageLog=true #enableXmlSourceDump=false #enableRetryLog=false #enableTrace=true #enableShellExecLog=true #enableTimeMeasureLog=true #enableImageMatchDebugLog=true #testResults= #testListDir= ## Screenshot -------------------- #screenshotScale=0.333333 #autoScreenshot=false #onChangedOnly=false #onCondition=false #onAction=false #onExpectation=false #onExecOperateCommand=false #onCheckCommand=false #onScrolling=false #manualScreenshot=false ## Image Matching -------------------- #imageMatchingScale= #imageMatchingThreshold= #imageMatchingCandidateCount= ## Appium -------------------- appiumServerUrl=http://127.0.0.1:4720/ appiumPath=appium appiumArgs=--session-override --relaxed-security #appiumArgsSeparator= #appiumServerStartupTimeoutSeconds= #appiumSessionStartupTimeoutSeconds= #implicitlyWaitSeconds= #appPackageFile= #appPackageDir= #packageOrBundleId= #startupPackageOrBundleId= #startupActivity= ## TestDriver -------------------- #resuseDriver= #retryMaxCount= #retryTimeoutSeconds= #retryIntervalSeconds= ## App operation -------------------- #appIconName= #tapAppIconMethod= #tapAppIconMacro= #shortWaitSeconds= #waitSecondsForAnimationComplete= #waitSecondsOnIsScreen= #waitSecondsForConnectionEnabled= #swipeDurationSeconds= #flickDurationSeconds= #swipeMarginRatio= #scrollVerticalMarginRatio= #scrollHorizontalMarginRatio= #tapHoldSeconds= #syncWaitSeconds= ## Custom -------------------- #CustomObject.scan.dir=src/test/kotlin ## Macro -------------------- #MacroObject.scan.dir=src/test/kotlin ## Spec-Report -------------------- #specReport.replace.MANUAL= #specReport.replace.MANUAL.reason= #specReport.replace.SKIP= #specReport.replace.SKIP.reason= ## misc #android.swipeOffsetY=-20 #ios.swipeOffsetY=-5 #xmlSourceRemovePattern= #boundsToRectRatio= #ios.selectIgnoreTypes=XCUIElementTypeCell,XCUIElementTypeApplication #android.titleSelector=<#action_bar||#toolbar||#app_bar>:descendant(${title}||@${title}) #ios.titleSelector=<.XCUIElementTypeNavigationBar>:descendant(.XCUIElementTypeStaticText&&${title}) #android.webTitleSelector=.android.webkit.WebView&&${webTitle} #ios.webTitleSelector=<.XCUIElementTypeWebView>:descendant(${webTitle}&&visible=false) #jquerySource=
多くのパラメーターは#でコメントアウトされています。必要になった場合は#を削除して設定を有効化します。 パラメーターの詳細についてはParametersを参照してください。
使用頻度の高いパラメーターのセクションを以下に紹介します。
Test Modeセクション
通常モードと無負荷実行モードの切り替えを行うことができます。
## Test mode -------------------- #noLoadRun=true
コメントを解除して
noLoadRun=true
を指定すると無負荷実行モードになります。無負荷実行モードでは実際のテスト実行を行わずテスト仕様書(Spec-Report)のみを出力します。
Logセクション
ログに関する設定を行うことができます。
## Log -------------------- logLanguage=ja #enableSyncLog=false #enableTestList=false #enableSpecReport=false #enableInnerMacroLog=true #enableInnerCommandLog=true #enableSilentLog=true #enableTapElementImageLog=true #enableXmlSourceDump=false #enableRetryLog=false #enableTrace=true #enableShellExecLog=true #enableTimeMeasureLog=true #enableImageMatchDebugLog=true #testResults= #testListDir=
logLanguage
ログの言語です。デフォルトは英語です。日本語に設定する場合は
logLanguage=ja
を指定します。
testResults
ログの出力ディレクトリを変更する場合は書き換えます。デフォルトはダウンロードディレクトリ下のTestResults
フォルダです。
Appiumセクション
Appiumに関する設定を行うことができます。(Appiumのより詳細な設定はtestConfigファイルで行います。)
## Appium -------------------- appiumServerUrl=http://127.0.0.1:4720/ appiumPath=appium appiumArgs=--session-override --relaxed-security #appiumArgsSeparator= #appiumServerStartupTimeoutSeconds= #appiumSessionStartupTimeoutSeconds= #implicitlyWaitSeconds= #appPackageFile= #appPackageDir= #packageOrBundleId= #startupPackageOrBundleId= #startupActivity=
appiumServerUrl
Appiumで使用するURLを変更したい場合は書き換えます。たとえばポート番号を4721に変更したい場合は以下のように書き換えます。
appiumServerUrl=http://127.0.0.1:4721/
appiumArgs
Appiumの起動オプションを変更したい場合は書き換えます。
日本語モードでのテストの実行
日本語に設定した状態で前回の記事で作成したプログラムを実行すると以下のように出力されます。
比較のために英語モードでの出力を以下に記載します。
これらの出力は単一のテストコードから出力しています。
このようにShiratesは日本語による可読性の高いログの出力をサポートしています。
Shiratesを使ってみよう
本記事はQiitaに転載したのでそちらをご覧ください。