Appium 模拟
您可能需要测试使用相机拍摄照片或扫描条形码的个应用程序,或者使用身份验证来保护登录或付款等敏感功能的个应用程序。如果要测试的设备在物理上不可用,则会出现问题。使用模拟,您可以测试个应用程序的这些方面,而无需访问物理设备。
”注意:“仅注入代码的应用程序支持模拟。要安装并启动打包的个应用程序,请将 ”installPackageApp“ 功能设置为 true。
生物识别
您可以在 Appium 测试中模拟指纹和人脸识别(仅 iOS)身份验证。使用以下参数和值指定要用于仿真的数据。
SimulationData
参数 | 值 |
---|---|
”authResult“ |
模拟结果:
|
”authType“
|
身份验证类型: 指纹 ”备注:“ 指纹”authType“ 也用于 FaceID。 |
”authResultDetails“ |
模拟失败或取消时的结果原因。当 authResult = Success 时,将该值保留为空。 authResult =失败
|
”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 存储库 中的示例。
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.0 为 100%
* /
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
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