Appium 模拟

您可能需要测试使用相机拍摄照片或扫描条形码的应用程序,或者使用身份验证来保护登录或付款等敏感功能的应用程序。如果要测试的设备在物理上不可用,则会出现问题。使用模拟,您可以测试应用程序的这些方面,而无需访问物理设备。

注: 仅注入代码的应用程序支持模拟。要安装并启动注入代码的应用程序,请将 installPackageApp 功能设置为 true。

生物识别

您可以在 Appium 测试中模拟指纹和人脸识别 (仅 iOS) 身份验证。使用以下参数和值指定要用于仿真的数据。

模拟数据

参数
authResult

模拟结果:

  • 成功

  • 失败

  • 取消

authType

身份验证类型:

指纹

备注: 指纹 authType 也用于 FaceID。

authResultDetails

模拟失败或取消时的结果原因。当 authResult = Success 时,将该值保留为空。

authResult = 失败

  • 无法识别
    正在使用的生物识别数据与注册的数据不匹配。例如,设备的所有者注册了他们的生物识别数据,而其他人尝试使用他们自己的数据解锁设备。

  • 锁定
    失败的尝试次数太多。
  • FingerIncomplete
    仅 Android: 手指移动太快。
  • 感应器脏
    仅 Android: 指纹传感器脏。
  • NoFingerprint 已注册
    仅 iOS: 否身份验证方法已在设备上注册。例如,设备的所有者没有注册他们的 TouchID/FaceID,但是正在测试的应用程序在某些时候需要 TouchID/FaceID。
 

authResult = 取消

  • 用户
    用户取消了身份验证
  • 系统
    系统取消了身份验证。

操作

指定测试期间要执行的仿真类型:

参数
操作

身份验证

后退到顶部

照片、条形码和二维码模拟

您可以模拟拍摄照片,或扫描 Appium 测试中的条形码或二维码。使用摄影机模拟时,可以指定要使用的图像,而不是摄影机的实际输出。

参数
内容类型 图像
文件名
任何文件名,包括后缀。
上载介质 介质应以 base64 编码。
操作

正在执行的仿真类型:

  • 条码

  • 照相机

注: 要关闭摄像机模拟,请将 uploadMedia 设置为“ 0 ”。

后退到顶部

代码示例

以下部分提供了将 Digital Lab 摄像机和身份验证模拟用于 Appium 的代码示例。有关使用 Appium 和 Digital Lab 的工作项目,请参阅 Digital Lab github 存储库.

Android 身份验证和相机模拟 - Java

示例代码使用 Java 客户端 v8。对于 Java 客户端 v7.x,请参阅 Digital Lab github repository 中的示例.

Copy code
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");
        //Simulations are supported only on packaged apps. The below capability instructs Digital Lab to install the packaged version of the app. Default value is 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{
            //Implicit wait
            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();
                //Perform biometric simulation
                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);
            }
            //load the photo before opening the camera
            System.out.println("Photo simulation result:" + cameraSimulation("image","cat.png","camera"));
            imageList.click();
            //The steps below are performed on the device's camera and correspond to a device with Android 12.
            //These steps may change depending on the device model/brand since the camera app might be different.
            driver.findElement(AppiumBy.accessibilityId("Take photo")).click();
            driver.findElement(AppiumBy.accessibilityId("Done")).click();
            //Barcode simulation sample usage:
            //System.out.println(cameraSimulation("image","QRCode.jpg","barcode"));
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (driver != null) driver.quit();
        }
    }
    /**
     * Biometric authentication simulation enable/update command.
     * @param authResult The simulate result: Failure, Success, or Cancel
     * @param authResultDetails The simulate reason when Failure/Cancel
     *     Failure: NotRecognized, Lockout, FingerIncomplete(Android only), SensorDirty(Android only), NoFingerprintRegistered(iOS only)
     *     Cancel: System, User
     * @return The result of 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");        

        //Execute the script and convert the result to a JSON string
        String simulationResult = new Gson().toJson(driver.executeScript("mc:sensorSimulation", sensorSimulationMap));
        //Return just the message value from simulationResult
        return new Gson().fromJson(simulationResult, JsonObject.class).get("message").getAsString();
    }
    /**
     *
     * @param contentType Image
     * @param fileName Any file name
     * @param action Action: barcode, camera
     * @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);
        //Execute the script and convert the result to a JSON string
        String simulationResult = new Gson().toJson(driver.executeScript("mc:sensorSimulation", sensorSimulationMap));
        //Return just the message value from simulationResult
        return new Gson().fromJson(simulationResult, JsonObject.class).get("message").getAsString();
    }
    /**
     *
     * @param elementId The id of the element to be swiped
     * @param direction Swipe direction. Mandatory value. Acceptable values are: up, down, left and right (case insensitive)
     * @param percent The size of the swipe as a percentage of the swipe area size. Valid values must be float numbers in range 0..1, where 1.0 is 100%
     */
    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

Copy code
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";
        //Update the below variable to indicate whether you want to use Appium v2 or the default Appium v1
        private static Boolean useAppiumV2 = true;

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

            //Digital Lab  embedded Appium capabilities                                                                                 
            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");

            //Simulations are supported only on packaged apps. The below capability instructs Digital Lab to install the packaged version of the app. Default value is 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]");

                //Implicit wait
                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();
                    //Perform biometric simulation
                    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);
                }
                //load the photo before opening the camera                
                Console.WriteLine("Photo simulation result:" + CameraSimulation(SimulationResources.cat, ImageFormat.Png, contentType: "image", fileName: "cat.png", action: "camera"));
                imageList.Click();
                //The steps below are performed on the device's camera and correspond to a device with Android 12.
                //These steps may change depending on the device model/brand since the camera app might be different.
                driver.FindElement(MobileBy.AccessibilityId("Take photo")).Click();
                driver.FindElement(MobileBy.AccessibilityId("Done")).Click();

                //Barcode simulation sample usage:
                //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>
        /// Biometric authentication simulation enable/update command.
        /// </summary>
        /// <param name="authResult">The simulate result, including Failure, Success, Cancel</param>
        /// <param name="authResultDetails">
        /// The simulate reason when Failure/Cancel
        /// Failure: NotRecognized, Lockout, FingerIncomplete(Android only), SensorDirty(Android only), NoFingerprintRegistered(iOS only)
        /// Cancel: System, User
        /// </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>
        /// Performs swipe on element
        /// </summary>        
        /// <param name="location">Object location</param>
        /// <param name="size">Object size</param>
        /// <param name="direction">Swipe direction. Mandatory value. Acceptable values are: up, down, left and right (case insensitive)</param>
        /// <param name="percent">The size of the swipe as a percentage of the swipe area size. Valid values must be float numbers in range 0..1, where 1.0 is 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