导入pom依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ceshiren</groupId>
<artifactId>appium_project</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.appium</groupId>
<artifactId>java-client</artifactId>
<version>9.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.23.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
启动应用
- 初始化
DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
desiredCapabilities.setCapability("platformName", "Android");
desiredCapabilities.setCapability("platformVersion", "13");
desiredCapabilities.setCapability("deviceName", "5cdbdc95");
desiredCapabilities.setCapability("appPackage", "com.xueqiu.android");
desiredCapabilities.setCapability("appActivity", ".view.WelcomeActivityAlias");
desiredCapabilities.setCapability("automationName", "uiautomator2");
desiredCapabilities.setCapability("ensureWebviewsHavePages", true);
desiredCapabilities.setCapability("nativeWebScreenshot", true);
desiredCapabilities.setCapability("newCommandTimeout", 3600);
desiredCapabilities.setCapability("connectHardwareKeyboard", true);
desiredCapabilities.setCapability("noReset", true);
URL url = new URL("http://127.0.0.1:4723/wd/hub");
driver = new AndroidDriver(url, desiredCapabilities);
- 热启动
driver.execute(LAUNCH_APP);
常用定位方式
- id
- accessibility-id
- xpath
常用交互
- click
- sendKeys
- clear
- getText
WebElement el1 = driver.findElement(AppiumBy.accessibilityId("Echo Box"));
el1.click();
WebElement el2 = driver.findElement(AppiumBy.accessibilityId("messageInput"));
el2.sendKeys("hello");
el2.clear();
el2.sendKeys("world");
WebElement el3 = driver.findElement(AppiumBy.className("android.widget.TextView"));
el3.click();
driver.navigate().back();
WebElement el4 = driver.findElement(AppiumBy.xpath("//android.widget.TextView[@text='The App']"));
String text = el4.getText();
assertEquals("The App",text);
driver.navigate().back();
等待方式
- 强制等待
- 隐式等待
- 显式等待
//强制等待
Thread.sleep(3000);
//隐式等待
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(15));
//显式等待
WebElement e1 = new WebDriverWait(driver,Duration.ofSeconds(3))
.until(ExpectedConditions.elementToBeClickable(
AppiumBy.id("com.xueqiu.android:id/home_search")
));
e1.click();
获取元素属性
- 是否可见:isDisplayed()
- 是否可用: isEnabled()
- 是否被选中:isSelected()
- 获取属性值:getAttribute
WebElement e2 = driver.findElement(AppiumBy.xpath("//android.widget.EditText[@resource-id=\"com.xueqiu.android:id/search_input_text\"]"));
String text = e2.getText();
System.out.println("文本内容:"+text);
boolean displayed = e2.isDisplayed();
System.out.println("元素是否可见:"+displayed);
String resourceId = e2.getAttribute("resource-id");
System.out.println("resource-id:"+resourceId);
String clickable = e2.getAttribute("long-clickable");
System.out.println("clickable:"+clickable);
boolean enabled = e2.isEnabled();
System.out.println("enabled:"+enabled);
Point location = e2.getLocation();
System.out.println("location:"+location);
Dimension size = e2.getSize();
System.out.println("size:"+size);
xpath函数
- 包含://*[contains(@属性,“属性值”)]
//*[contains(@text,"阿里巴巴-SW")]
xpath轴
- 父子
//*[@text="BABA"]/..
//*[@text="BABA"]/parent::*
//*[@text="BABA"]/child
- 爷孙
//*[@text="BABA"]/../..
//*[@text="BABA"]/parent::*/parent::*
//*[@text="BABA"]/child/child
- 祖先
返回当前节点的所有祖先
//*[@text="BABA"]/ancestor::android.widget.LinearLayout
显式指定要返回的祖先
//*[@text="BABA"]/ancestor::android.widget.LinearLayout[1]
- 兄弟姐妹
节点后的兄弟姐妹
//android.widget.TextView[@text="-2.23%"]/following-sibling::*
//android.widget.TextView[@text="-2.23%"]/following-sibling::*[@text="价格"]
节点前的兄弟姐妹
//android.widget.TextView[@text="-2.23%"]/preceding-sibling::*
//android.widget.TextView[@text="-2.23%"]/preceding-sibling::*[@text="76.65"]
xpath运算符
- and:交集
- or:并集
//*[contains(@text,"阿里巴巴-SW") and @resource-id="com.xueqiu.android:id/name"]
//*[contains(@text,"阿里巴巴-SW") or @resource-id="com.xueqiu.android:id/name"]
原生定位
- 基础定位
- 组合定位
#基础定位,注意用\转义双引号
WebElement e2 = driver.findElement(AppiumBy.androidUIAutomator("new UiSelector().resourceId(\"com.xueqiu.android:id/search_input_text\")"));
e2.sendKeys("alibaba");
#组合定位,注意用\转义双引号
WebElement e3 = driver.findElement(AppiumBy.androidUIAutomator("new UiSelector().resourceId(\"com.xueqiu.android:id/name\").text(\"阿里巴巴\")"));
e3.click();
cssSelector定位
#注意要用\\转义特殊符号
WebElement e2 = driver.findElement(AppiumBy.cssSelector("#com\\.xueqiu\\.android\\:id\\/search_input_text"));
webView自动化测试
- 电脑端安装Edge浏览器,进入触屏调试页:edge://inspect
- 移动端安装chrome浏览器并进入网页
- 匹配关系表:https://raw.githubusercontent.com/appium/appium-chromedriver/master/config/mapping.json
//手机端需要的chrome版本对应的chromedriver存放位置
desiredCapabilities.setCapability("chromedriverExecutableDir", "D:\\study\\chromedriver124.0.6367.155");
//版本匹配关系表,直接copy网站信息写成json文件存放在本地,并写对应存放位置
desiredCapabilities.setCapability("chromedriverChromeMappingFile", "D:\\study\\chromedriver124.0.6367.155\\mapping.json");
//chromedriver的log
desiredCapabilities.setCapability("showChromedriverLog", true);
//切换上下文,从原生页面切换到webview
Set<String> contextHandles = driver.getContextHandles();
driver.context(contextHandles.toArray()[1].toString());
//使用html的标签定位
String text1 = driver.findElement(By.xpath("//h2")).getText();
System.out.println(text1);
//有多个webview的情况下切换句柄,到下一个窗口
Set<String> windowHandles = driver.getWindowHandles();
driver.switchTo().window(windowHandles.toArray()[0].toString());
//使用html的标签定位下一个窗口的元素
String text2 = driver.findElement(By.xpath("//h2")).getText();
System.out.println(text2);
最后附上一个app企业微信的添加成员案例,使用了po模式:
https://github.com/HandsomeBoy1221/app-po