Appium 模拟

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

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

生物识别

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

SimulationData

参数
”authResult“

模拟结果:

  • 成功

  • 失败

  • 取消

”authType“

身份验证类型:

指纹

”备注:“ 指纹”authType“ 也用于 FaceID。

”authResultDetails“

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

authResult =失败

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

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

”authResult =取消“

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

操作

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

参数
操作

身份验证

后退到顶部

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

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

参数
”contentType“ 图像
”filename“
任何文件名,包括后缀。
”上载介质“ 介质应以 base64 编码。
”操作“

正在执行的仿真类型:

  • 条码

  • 照相机

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

后退到顶部

代码示例

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

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

示例代码使用 Java 客户端 v8。有关 Java - Client v7.x,请参见 UFTM github 存储库 中的示例。

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://uftm-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("uftm:oauthClientId", "oauth2-tGR1nN6ZxLQNMrKH4Hq9@microfocus.com");
        caps.setCapability("uftm:oauthClientSecret", "A3BNk1Tc4gbf7o2jDU5m");
        caps.setCapability("uftm:tenantId", "999999999");
        //Simulations are supported only on packaged apps. 以下功能指示UFTM安装个应用程序的打包版本。 Default value is false
        caps.setCapability("uftm:installPackagedApp", true);
        driver = new AndroidDriver(new URL(SERVER + "/wd/hub"), caps);
        System.out.println("UFTM 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:" + camera-simulation (" image" ," cat.png" ," camera");
imageList.click ();
//以下步骤在设备的照相机上执行,对应于 Android2 的设备。
            //根据设备型号/品牌的不同,这些步骤可能会有所不同,因为摄影机个应用程序可能会有所不同。
            driver.findElement (AppiumBy.accessibilityId ("拍照")).click ();
driver.findElement (AppiumBy.accessibilityId ("完成")).click ();
//条形码模拟示例用法: 
            //System.out.println (camera-simulation (" image" ," QRCode.jpg" ," barcode"));
} catch (Exception e){
e.printStackTrace ();
} finally {
if (driver != null)driver.quit ();
}
}
/* *
*生物特征验证仿真启用/更新命令。
     * @ param authResult 模拟结果: 失败、Success 或取消* @ param authResultDetails 失败/取消时的模拟原因*失败: NotRecognized、Lockout、FingerIncomplete (仅 Android)、SensorDirty (仅 Android)、NoFingerprintRegistration (仅 iOS)
*取消: 系统,用户* @ return ExecuteScript 的结果* /
private static String biometricSimulation (String authResult ,String authResultDetails)throws InterruptedException {
HashMap < String ,Object > sensorSimulationMap = new HashMap < String ,Object > ();
HashMap < String ,String > simulation Data = new HashMap < String ,String > ();
simulation data.put (" authResult" ,authResult);
simulation.put (" authType" ,"指纹");
simulation.put (" authResultDetails" ,authResultDetails);

sensorSimulationMap.put (" simulation-data" ,simulation-data);
sensorSimulationMap.put (" action" ," authentication");
sensorSimulationMap.put (" action" ," authentication");

//执行脚本并将结果转换为 JSON 字符串 String simulation Result = new Gson ().toJson (driver.executeScript (" mc: sensorSimulation" ,sensorSimulationMap));
//仅返回模拟结果中的消息值 return new Gson ().fromJson (simulation_Result ,JsonObject.class).get (" message").getAsString ();
}
/* *
*
* @ param contentType 图像* @ param fileName 任何文件名* @ param action 操作:条形码,相机* @ return
* /
private static String camera (String contentType ,String fileName ,String action)throws IOException ,URISyntaxException ,InterruptedException {
Path path = Path.get (Objects.requireNonNull (Resources.getResource (" photo/" + fileName)).toURI ());
byte [] bytes = Files.readAllBytes (path);
String encodedString = Base64.getEncoder ().encodeToString (bytes);
HashMap <字符串,字符串> sensorSimulationMap = new HashMap < > ();
sensorSimulationMap.put ("上载介质" ,encodedString);
sensorSimulationMap.put (" contentType" ,contentType);
sensorSimulationMap.put (" fileName" ,fileName);
sensorSimulationMap.put (" action" ,action);
//执行脚本并将结果转换为 JSON 字符串 String simulation Result = new Gson ().toJson (driver.executeScript (" mc: sensorSimulation" ,sensorSimulationMap));
//仅返回模拟结果中的消息值 return new Gson ().fromJson (simulation_Result ,JsonObject.class).get (" message").getAsString ();
}
/* *
*
* @ param elementId 要扫描的元素的 ID
* @ param direction 必需的值。可接受的值包括: up、down、left 和 right (不区分大小写)
* @ param percent 以扫描区域大小的百分比表示的扫描大小。有效值必须是范围为 0..1 的浮点数,其中 1.0100%
* /
private static void swpeElement (String elementId ,String direction ,double percent){
HashMap <字符串,对象> swpeMap = new HashMap < > ();
swpeMap.put (" elementId" ,elementId);
swpeMap.put ("方向" ,方向);
swpeMap.put (" percent" ,percent);
driver.executeScript (" mobile: swpeGesture" ,swpeMap);
}
}

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 UFTM_SERVER = "http://uftm-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();

            appiumOptions.AddAdditionalAppiumOption("appium:udid", "8BSX1EDTD");            
            appiumOptions.AddAdditionalAppiumOption("appium:appPackage", "com.Advantage.aShopping");
            appiumOptions.AddAdditionalAppiumOption("appium:appActivity", "com.Advantage.aShopping.SplashActivity");
            appiumOptions.AddAdditionalAppiumOption("uftm:oauthClientId", "oauth2-UNmB6dXe4XNzJpjY4GSg@microfocus.com");
            appiumOptions.AddAdditionalAppiumOption("uftm:oauthClientSecret", "3Rd1wgB0g71KBT6S2tv3");
            appiumOptions.AddAdditionalAppiumOption("uftm:tenantId", "999999999");

//仅在注入代码的应用程序上受支持模拟。以下功能指示 UFTM 安装个应用程序的打包版本。默认值为 false
            appiumOptions.AddAdditionalAppiumOption("uftm:installPackagedApp", true);
            System.Uri url = new System.Uri(string.Format("{0}/wd/hub", UFTM_SERVER));            

            try
            {
                driver = new AndroidDriver(url, appiumOptions);
                System.Console.WriteLine("UFTM 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 ("是否要使用指纹身份验证登录?"))
                {
driver.FindElement (MobileBy.Id (" Android: id/Button1")).单击();
//执行生物统计模拟 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 ("照片模拟结果: "+ CameraSimulation (SimulationResources.cat ,ImageFormat.Png ,contentType: " image" ,fileName: " cat.png" ,action: " camera");
imageList.单击();
//以下步骤在设备的照相机上执行,对应于 Android2 的设备。
                //根据设备型号/品牌的不同,这些步骤可能会有所不同,因为摄影机个应用程序可能会有所不同。
                driver.FindElement (MobileBy.AccessibilityId ("拍照")).单击();
driver.FindElement (MobileBy.AccessibilityId ("完成")).单击();

//条形码模拟示例用法: 
                //Console.WriteLine (CameraSimulation (SimulationResources.QRCode ,ImageFormat.Png ,contentType: " image" ,fileName: “QRCode.png”,操作: " barcode"));
}
catch (异常e)
{
Console.WriteLine (e.StackTrace);
}
finally
{
if (driver != null)
driver.Quit ();
}
}

//<摘要>
///生物身份验证模拟启用/更新命令。
        //</summary >
///< param name =" authResult" >模拟结果,包括失败、Success、取消</param >
///< param name =" authResultDetails" >
///The simulation reason when 失败/取消///失败: NotRecognized、Lockout、FingerIncomplete (仅 Android)、SensorDirty (仅 Android)、NoFingerprintRegistration (仅 iOS)
///取消: 系统,用户//</param >
///<返回> ExecuteScript 的结果</返回>
public static string BiometricSimulation (string authResult ,string authResultDetails ="")
{
Dictionary < string ,object > sensorSimulationMap = new Dictionary < string ,object > ();字典< string ,string > simulation Data = new Dictionary < string ,string >
{
{" authResult" ,authResult} ,
{" authType" ,"指纹"} ,
{" authResultDetails" ,authResultDetails}
} ;
sensorSimulationMap.添加(" simulation-data" ,simulation-data);
sensorSimulationMap.添加(" action" ," authentication");

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

//<摘要>
///
//</summary >
///< param name =" picture" > </param >
///< param name =" format" > </param >
///< param name =" contentType" > image </param >
///< param name =" fileName" > </param >
///< param name =" action" >操作:条形码,照相机</param >
///<返回> </返回>
public static string CameraSimulation (Bitmap picture ,ImageFormat format format ,string contentType ,string fileName ,string action)
{
? ? MemoryStream 毫秒= new MemoryStream ();
image.保存(毫秒,format);
Byte [] bytes =毫秒.ToArray ();
string encodeString = Convert.ToBase64String (bytes);

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

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


//<摘要>
///在元素上执行滑动//</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 swpeElement (Point location ,Size size ,String direction ,double percent)
{
Dictionary < string ,object > swpeMap = new Dictionary < string ,object >
{
{" left" ,0} ,
{" top" ,0} ,
{" width" ,size.Width} ,
{" height" ,size.Height + location.Y-30} ,
{" direction" ,direction} ,
{" percent" ,percent}
} ;
            
driver.ExecuteScript (" mobile: swpeGesture" ,swpeMap);
}

}
}

 

有关其他代码示例,请参见 Appium 集成Appium 代码示例- Java