Appiumシミュレーション

写真の撮影やバーコードのスキャンにカメラを使用するアプリ、またはサインオンや支払いなどの機密機能を保護するために認証を使用するアプリをテストする必要がある場合があります。テストしているデバイスが物理的に利用できない場合、これは問題を引き起こします。シミュレーションを使用すると、物理デバイスにアクセスしなくても、アプリのこれらの側面をテストできます。

注: シミュレーションは、パッケージ化されたアプリでのみサポートされます。パッケージ化されたアプリをインストールして起動するには、機能installPackageAppをtrueに設定します。

バイオメトリクス

Appiumテストで指紋とFace ID (iOSのみ) の認証をシミュレートできます。以下のパラメーターと値を使用して、シミュレーションに使用するデータを指定します。

SimulationData

パラメーター
authResult

シミュレーションの結果:

  • 成功

  • 失敗

  • キャンセル

authType

認証タイプ:

指紋

注: 指紋authTypeはFaceIDにも使用されます。

authResultDetails

シミュレーションが失敗またはキャンセルされた場合の結果の理由。authResult = Successの場合、この値は空のままにします。

authResult = Failure

  • NotRecognized
    使用されている生体認証データが登録データと一致しません。たとえば、デバイスの所有者が生体認証データを登録し、他の誰かが自分のデータを使用してデバイスのロックを解除しようとしました。

  • Lockout
    失敗の回数が上限を超過しました。
  • FingerIncomplete
    Androidのみ: 指の動きが速すぎます。
  • SensorDirty
    Androidのみ: 指紋センサーが汚れています。
  • NoFingerprintRegistered
    iOSのみ: デバイスに認証方法が登録されていません。たとえば、デバイスの所有者はTouchID/FaceIDを登録していませんが、テスト対象のアプリケーションは、ある時点でTouchID/FaceIDを必要とします。
 

authResult = Cancel

  • User
    ユーザーが認証をキャンセルしました
  • System
    システムは認証をキャンセルしました。

action

これは、テスト中に実行するシミュレーションのタイプを指定します。

パラメーター
action

認証

トップに戻る

写真、バーコード、QRコードのシミュレーション

Appiumテストでは、写真を撮ったり、バーコードやQRコードをスキャンしたりすることをシミュレートできます。カメラシミュレーションを使用する場合は、カメラの実際の出力の代わりに使用する画像を指定します。

パラメーター
contentType 画像
filename
サフィックスを含む任意のファイル名。
uploadMedia メディアはbase64でエンコードする必要があります。
action

実行されているシミュレーションのタイプ:

  • バーコード

  • カメラ

注: カメラシミュレーションをオフにするには、uploadMediaを「0」に設定します。

トップに戻る

コードサンプル

次のセクションでは、Digital LabカメラとAppiumでの認証シミュレーションを使用するためのコードサンプルを提供します。AppiumとDigital Labを使用した作業プロジェクトについては、Digital Lab githubリポジトリを参照してください。

Android認証とカメラシミュレーション - Java

サンプルコードはJava-Client v8を使用しています。Java-Client v7.xについては、Digital Lab githubリポジトリの例を参照してください。

コードをコピーする
import com.google.common.io.Resources;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import io.appium.java_client.AppiumBy;
import io.appium.java_client.TouchAction;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.options.UiAutomator2Options;
import io.appium.java_client.touch.offset.PointOption;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.RemoteWebElement;
import java.awt.*;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.Base64;
import java.util.HashMap;
import java.util.Objects;
public class Simulation {
    private static AndroidDriver driver;
    private static String SERVER = "https://digitallab-server:8443";
    public static void main(String[] args) throws MalformedURLException {
        UiAutomator2Options caps = new UiAutomator2Options();
        caps.setCapability("platformName", "Android");
        caps.setCapability("udid", "8BSX1EDTD");
        caps.setCapability("automationName", "UiAutomator2");
        caps.setCapability("appPackage", "com.Advantage.aShopping");
        caps.setCapability("appActivity", "com.Advantage.aShopping.SplashActivity");
        caps.setCapability("dl:oauthClientId", "oauth2-tGR1nN6ZxLQNMrKH4Hq9@opentext.com");
        caps.setCapability("dl:oauthClientSecret", "A3BNk1Tc4gbf7o2jDU5m");
        caps.setCapability("dl:tenantId", "999999999");
        //シミュレーションは、パッケージアプリでのみサポートされます。以下の機能は、Digital Labにパッケージバージョンのアプリをインストールするように指示します。デフォルト値はfalse
        caps.setCapability("dl:installPackagedApp", true);
        driver = new AndroidDriver(new URL(SERVER + "/wd/hub"), caps);
        System.out.println("Digital Lab session was successfully created [Android device]");
        try{
            //暗黙の待機
            driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
            driver.findElement(AppiumBy.id("imageViewMenu")).click();
            driver.findElement(AppiumBy.id("textViewMenuUser")).click();
            WebElement username = driver.findElement(AppiumBy.xpath("//*[@resource-id='com.Advantage.aShopping:id/AosEditTextLoginUserName']/android.widget.EditText[1]"));
            username.click();
            username.sendKeys("Mercury");
            WebElement password = driver.findElement(AppiumBy.xpath("//*[@resource-id='com.Advantage.aShopping:id/AosEditTextLoginPassword']/android.widget.EditText[1]"));
            password.click();
            password.sendKeys("Mercury");
            driver.findElement(AppiumBy.id("buttonLogin")).click();
            Thread.sleep(3000);
            String message = driver.findElement(AppiumBy.id("android:id/message")).getText();
            if(message.contains("Would you like to use fingerprint authentication for logging in ?")){
                driver.findElement(AppiumBy.id("android:id/button1")).click();
                //生体認証シミュレーションを実行します
                System.out.println("Biometric simulation result:" + biometricSimulation("Success",""));
            }
            driver.findElement(AppiumBy.androidUIAutomator("new UiSelector().textContains(\"LAPTOPS\")")).click();
            driver.findElement(AppiumBy.androidUIAutomator("new UiSelector().textContains(\"HP CHROMEBOOK 14 G1(ENERGY STAR)\")")).click();
            int requiredSwipes = driver.findElements(AppiumBy.xpath("//*[@resource-id='com.Advantage.aShopping:id/linearLayoutImagesLocation']/android.widget.FrameLayout")).size();
            WebElement imageList = driver.findElement(AppiumBy.id("viewPagerImagesOfProducts"));
            for(int i = 1;i <= requiredSwipes;i++){
                swipeElement(((RemoteWebElement) imageList).getId(),"up", 1);
            }
            //カメラを開く前に写真を読み込む
            System.out.println("Photo simulation result:" + cameraSimulation("image","cat.png","camera"));
            imageList.click();
            //以下の手順はデバイスのカメラで実行され、Android 12を搭載したデバイスに対応します。
            //カメラアプリが異なる場合があるため、これらの手順はデバイスのモデル/ブランドによって異なる場合があります。
            driver.findElement(AppiumBy.accessibilityId("Take photo")).click();
            driver.findElement(AppiumBy.accessibilityId("Done")).click();
            //バーコードシミュレーションのサンプル使用法:
            //System.out.println(cameraSimulation("image","QRCode.jpg","barcode"));
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (driver != null) driver.quit();
        }
    }
    /**
     * 生体認証シミュレーションの有効化/更新コマンド。
     * @param authResultシミュレート結果: 失敗、成功、またはキャンセル
     * @param authResultDetails失敗/キャンセル時のシミュレート理由
     * 失敗: NotRecognized、Lockout、FingerIncomplete(Androidのみ)、SensorDirty(Androidのみ)、NoFingerprintRegistered(iOSのみ)
     * キャンセル: システム、ユーザー
     *@return ExecuteScriptの結果
     */
    private static String biometricSimulation(String authResult, String authResultDetails) throws InterruptedException {
        HashMap<String, Object> sensorSimulationMap = new HashMap<String, Object>();
        HashMap<String, String> simulationData = new HashMap<String, String>();
        simulationData.put("authResult", authResult);
        simulationData.put("authType", "Fingerprint");
        simulationData.put("authResultDetails", authResultDetails);

        sensorSimulationMap.put("simulationData", simulationData);
        sensorSimulationMap.put("action", "authentication");
        sensorSimulationMap.put("action", "authentication");        

        //スクリプトを実行し、結果をJSON文字列に変換します
        String simulationResult = new Gson().toJson(driver.executeScript("mc:sensorSimulation", sensorSimulationMap));
        //simulationResultからメッセージ値のみを返します
        return new Gson().fromJson(simulationResult, JsonObject.class).get("message").getAsString();
    }
    /**
     *
     *@param contentType画像
     *@param fileName任意のファイル名
     *@param actionアクション: バーコード、カメラ
     *@return
     */
    private static String cameraSimulation(String contentType, String fileName, String action) throws IOException, URISyntaxException, InterruptedException {
        Path path = Paths.get(Objects.requireNonNull(Resources.getResource("photo/" + fileName)).toURI());
        byte[] bytes = Files.readAllBytes(path);
        String encodedString = Base64.getEncoder().encodeToString(bytes);
        HashMap<String, String> sensorSimulationMap =  new HashMap<>();
        sensorSimulationMap.put("uploadMedia", encodedString);
        sensorSimulationMap.put("contentType", contentType);
        sensorSimulationMap.put("fileName", fileName);
        sensorSimulationMap.put("action", action);
        //スクリプトを実行し、結果をJSON文字列に変換します
        String simulationResult = new Gson().toJson(driver.executeScript("mc:sensorSimulation", sensorSimulationMap));
        //simulationResultからメッセージ値のみを返します
        return new Gson().fromJson(simulationResult, JsonObject.class).get("message").getAsString();
    }
    /**
     *
     *@param elementIdスワイプする要素のID
     *@param direction方向をスワイプします。必須の値。許容値は次のとおりです。up、down、left、right (大文字と小文字は区別されません)
     *@param percentスワイプ領域サイズのパーセンテージとしてのスワイプのサイズ。有効な値は、範囲0..1の浮動小数点数である必要があります。ここで、1.0100%
     */
    private static void swipeElement(String elementId, String direction, double percent){
        HashMap<String, Object> swipeMap =  new HashMap<>();
        swipeMap.put("elementId", elementId);
        swipeMap.put("direction", direction);
        swipeMap.put("percent", percent);
        driver.executeScript("mobile: swipeGesture", swipeMap);
    }
}

Android認証とカメラシミュレーション - C# .Net

コードをコピーする
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Enums;
using OpenQA.Selenium.Appium.Android;
using OpenQA.Selenium;
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Threading;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.IO;
using System.Drawing.Imaging;
using System.Drawing;
using Appium_Simulations.Resources;
using OpenQA.Selenium.Remote;

namespace Appium_Simulations
{
    public class Android
    {
        public static AndroidDriver driver;
        public static String DL_SERVER = "http://digitallab-server:8080";
        //以下の変数を更新して、Appium v2とデフォルトのAppium v1のどちらを使用するかを示します。
        private static Boolean useAppiumV2 = true;

        static void Main(string[] args)
        {            
            AppiumOptions appiumOptions = new AppiumOptions();

            //Digital Lab組み込みAppium機能                                                                                 
            appiumOptions.AddAdditionalAppiumOption("appium:udid", "8BSX1EDTD");            
            appiumOptions.AddAdditionalAppiumOption("appium:appPackage", "com.Advantage.aShopping");
            appiumOptions.AddAdditionalAppiumOption("appium:appActivity", "com.Advantage.aShopping.SplashActivity");
            appiumOptions.AddAdditionalAppiumOption("dl:oauthClientId", "oauth2-UNmB6dXe4XNzJpjY4GSg@opentext.com");
            appiumOptions.AddAdditionalAppiumOption("dl:oauthClientSecret", "3Rd1wgB0g71KBT6S2tv3");
            appiumOptions.AddAdditionalAppiumOption("dl:tenantId", "999999999");

            //シミュレーションは、パッケージアプリでのみサポートされます。以下の機能は、Digital Labにパッケージバージョンのアプリをインストールするように指示します。デフォルト値はfalse
            appiumOptions.AddAdditionalAppiumOption("dl:installPackagedApp", true);
            System.Uri url = new System.Uri(string.Format("{0}/wd/hub", DL_SERVER));            

            try
            {
                driver = new AndroidDriver(url, appiumOptions);
                System.Console.WriteLine("Digital Lab session was successfully created [Android device]");

                //暗黙の待機
                driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
                driver.FindElement(MobileBy.Id("imageViewMenu")).Click();
                driver.FindElement(MobileBy.Id("textViewMenuUser")).Click();
                WebElement username = driver.FindElement(MobileBy.XPath("//*[@resource-id='com.Advantage.aShopping:id/AosEditTextLoginUserName']/android.widget.EditText[1]"));
                username.Click();
                username.SendKeys("Mercury");
                WebElement password = driver.FindElement(MobileBy.XPath("//*[@resource-id='com.Advantage.aShopping:id/AosEditTextLoginPassword']/android.widget.EditText[1]"));
                password.Click();
                password.SendKeys("Mercury");
                driver.FindElement(MobileBy.Id("buttonLogin")).Click();
                Thread.Sleep(3000);
                String message = driver.FindElement(MobileBy.Id("android:id/message")).Text;
                if (message.Contains("Would you like to use fingerprint authentication for logging in ?"))
                {
                    driver.FindElement(MobileBy.Id("android:id/button1")).Click();
                    //生体認証シミュレーションを実行します
                    Console.WriteLine("Biometric simulation result:" + BiometricSimulation("Success", ""));
                }
                driver.FindElement(MobileBy.AndroidUIAutomator("new UiSelector().textContains(\"LAPTOPS\")")).Click();
                driver.FindElement(MobileBy.AndroidUIAutomator("new UiSelector().textContains(\"HP CHROMEBOOK 14 G1(ENERGY STAR)\")")).Click();
                int requiredSwipes = driver.FindElements(MobileBy.XPath("//*[@resource-id='com.Advantage.aShopping:id/linearLayoutImagesLocation']/android.widget.FrameLayout")).Count;
                WebElement imageList = driver.FindElement(MobileBy.Id("viewPagerImagesOfProducts"));
                for (int i = 1; i <= requiredSwipes; i++)
                {                                        
                    swipeElement(imageList.Location, imageList.Size, "up", 1);
                }
                //カメラを開く前に写真を読み込む                
                Console.WriteLine("Photo simulation result:" + CameraSimulation(SimulationResources.cat, ImageFormat.Png, contentType: "image", fileName: "cat.png", action: "camera"));
                imageList.Click();
                //以下の手順はデバイスのカメラで実行され、Android 12を搭載したデバイスに対応します。
                //カメラアプリが異なる場合があるため、これらの手順はデバイスのモデル/ブランドによって異なる場合があります。
                driver.FindElement(MobileBy.AccessibilityId("Take photo")).Click();
                driver.FindElement(MobileBy.AccessibilityId("Done")).Click();

                //バーコードシミュレーションのサンプル使用法:
                //Console.WriteLine(CameraSimulation(SimulationResources.QRCode, ImageFormat.Png, contentType: "image", fileName: "QRCode.png", action: "barcode"));                
            }
            catch (Exception e)
            {
                Console.WriteLine(e.StackTrace);
            }
            finally
            {
                if (driver != null)
                    driver.Quit();
            }
        }

        /// <summary>
        /// 生体認証シミュレーションの有効化/更新コマンド。
        /// </summary>
        /// <param name="authResult">失敗、成功、キャンセルなどのシミュレーション結果</param>
        /// <param name="authResultDetails">
        /// 失敗/キャンセル時のシミュレート理由
        /// 失敗: NotRecognized、Lockout、FingerIncomplete (Androidのみ)、SensorDirty(Androidのみ)、NoFingerprintRegistered(iOSのみ)
        /// キャンセル: システム、ユーザー
        /// </param>
        /// <returns>The result of ExecuteScript</returns>
        public static string BiometricSimulation(string authResult, string authResultDetails = "")
        {
            Dictionary<string, object> sensorSimulationMap = new Dictionary<string, object>();
            Dictionary<string, string> simulationData = new Dictionary<string, string>
            {
                { "authResult", authResult },
                { "authType", "Fingerprint" },
                { "authResultDetails", authResultDetails }
            };
            sensorSimulationMap.Add("simulationData", simulationData);
            sensorSimulationMap.Add("action", "authentication");                       

            string simulationResult = JsonConvert.SerializeObject(driver.ExecuteScript("mc:sensorSimulation", sensorSimulationMap));
            return JToken.Parse(simulationResult)["message"].ToString();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="picture"></param>
        /// <param name="format"></param>
        /// <param name="contentType">image</param>
        /// <param name="fileName"></param>
        /// <param name="action">Action: barcode, camera</param>
        /// <returns></returns>
        public static string CameraSimulation(Bitmap picture, ImageFormat format, string contentType, string fileName, string action)
        {
            MemoryStream ms = new MemoryStream();
            picture.Save(ms, format);
            Byte[] bytes = ms.ToArray();
            string encodeString = Convert.ToBase64String(bytes);

            Dictionary<string, string> sensorSimulationMap = new Dictionary<string, string>
            {
                { "uploadMedia", encodeString },
                { "contentType", contentType },
                { "fileName", fileName },
                { "action", action }
            };

            string simulationResult = JsonConvert.SerializeObject(driver.ExecuteScript("mc:sensorSimulation", sensorSimulationMap));
            return JToken.Parse(simulationResult)["message"].ToString();
        }


        /// <summary>
        /// 要素をスワイプします
        /// </summary>        
        /// <param name="location">オブジェクトの場所</param>
        /// <param name="size">オブジェクトサイズ</param>
        /// <param name="direction">方向をスワイプします。必須の値。許容値は次のとおりです。up、down、left、right (大文字と小文字は区別されません)</param>
        /// <param name="percent">スワイプのサイズ (スワイプのパーセンテージ) エリアサイズ。有効な値は、範囲0..1の浮動小数点数である必要があります。1.0は100%です</param>

        private static void swipeElement(Point location, Size size, String direction, double percent)
        {            
            Dictionary<string, object> swipeMap = new Dictionary<string, object>
            {
                { "left", 0},
                { "top", 0},
                { "width", size.Width },
                { "height", size.Height + location.Y - 30},
                { "direction", direction },
                { "percent", percent }
            };
            
            driver.ExecuteScript("mobile: swipeGesture", swipeMap);
        }

    }
}

 

追加のコードサンプルについては、Appiumの統合およびAppiumコード例 - Javaを参照してください。