Appium自动化Windows APP

前提条件
环境搭建
  • 打开Windows PC的开发者模式
  • 下载Windows SDK并默认安装
  • 下载Windows driver并默认安装
  • 运行WinAppDriver.exe(记得要用admin权限运行), 默认路径 (C:\Program Files (x86)\Windows Application Driver)

可以自定义地址或端口:

1
2
3
WinAppDriver.exe 4727
WinAppDriver.exe 127.0.0.1 4725
WinAppDriver.exe 127.0.0.1 4723/wd/hub

如下图:
20190809134649856.png

Windows 自动化脚本

运行脚本前要打开 WinAppDriver.exe
对于Windows App来说,只需要传一个app capabilities 即可。
对于UWP的App,app对应的值为Application Id(App ID)。关于如何获取APP ID,可以使用powershell命令get-StartApps来获取,打开powershell终端运行:get-StartApps | select-string "计算器"即可获取值(运行命令之前先打开计算器)。以下是java样例代码:

1
2
3
4
DesiredCapabilities cap = new DesiredCapabilities();
cap.setCapability("app", "LexisNexisAPAC.LexisRed_wsek3cqrhvvz2!App");
driver = new WindowsDriver(new URL("http://127.0.0.1:4723"), cap);
driver.findElementByAccessibilityId("CalculatorResults");

对于经典的Windows App,app对应的值为可执行的.exe文件路径。以下是java样例代码:

1
2
3
4
5
6
7
8
// Launch Notepad
DesiredCapabilities cap= new DesiredCapabilities();
cap.SetCapability("app", "C:\\Windows\\System32\\notepad.exe");
cap.SetCapability("appArguments", "MyTestFile.txt");
cap.SetCapability("appWorkingDir", "C:\\MyTestFolder");
driver= new WindowsDriver(new URL("http://127.0.0.1:4723"), cap);
// Use the session to control the app
driver.FindElementByClassName("Edit").SendKeys("This is some text");
Windows定位元素

使用Windows SDK提供的工具inspect.exeC:\Program Files (x86)\Windows Kits\10\bin\x86或者C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\x64根据系统查看)来定位,详情查看inspect,或者使用AccExplorer32UISpy定位。
支持的定位方式:

API 定位方法 对应inspect.exe的属性 例子
FindElementByAccessibilityId accessibility id AutomationId AppNameTitle
FindElementByClassName class name ClassName TextBlock
FindElementById id RuntimeId (decimal) 42.333896.3.1
FindElementByName name Name Calculator
FindElementByTagName tag name LocalizedControlType (upper camel case) Text
FindElementByXPath xpath Any //Button[0]
计算器的例子

Python(GitHub):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import unittest
from appium import webdriver


class WindowsCalculatorTest(unittest.TestCase):

@classmethod
def setUpClass(self):
# set up appium
desired_caps = {}
desired_caps["app"] = "Microsoft.WindowsCalculator_8wekyb3d8bbwe!App"
self.driver = webdriver.Remote(command_executor='http://127.0.0.1:4723', desired_capabilities=desired_caps)

@classmethod
def tearDownClass(self):
self.driver.quit()

def getresults(self):
displaytext = self.driver.find_element_by_accessibility_id("CalculatorResults").text
displaytext = displaytext.strip("显示为 ")
displaytext = displaytext.rstrip(' ')
displaytext = displaytext.lstrip(' ')
return displaytext

def test_addition(self):
self.driver.find_element_by_name("一").click()
self.driver.find_element_by_name("加").click()
self.driver.find_element_by_name("七").click()
self.driver.find_element_by_name("等于").click()
self.assertEqual(self.getresults(), "8")

def test_combination(self):
self.driver.find_element_by_name("七").click()
self.driver.find_element_by_name("乘以").click()
self.driver.find_element_by_name("九").click()
self.driver.find_element_by_name("加").click()
self.driver.find_element_by_name("一").click()
self.driver.find_element_by_name("等于").click()
self.driver.find_element_by_name("除以").click()
self.driver.find_element_by_name("八").click()
self.driver.find_element_by_name("等于").click()
self.assertEqual(self.getresults(), "8")

def test_division(self):
self.driver.find_element_by_name("八").click()
self.driver.find_element_by_name("八").click()
self.driver.find_element_by_name("除以").click()
self.driver.find_element_by_name("一").click()
self.driver.find_element_by_name("一").click()
self.driver.find_element_by_name("等于").click()
self.assertEqual(self.getresults(), "8")

def test_multiplication(self):
self.driver.find_element_by_name("九").click()
self.driver.find_element_by_name("乘以").click()
self.driver.find_element_by_name("九").click()
self.driver.find_element_by_name("等于").click()
self.assertEqual(self.getresults(), "81")

def test_subtraction(self):
self.driver.find_element_by_name("九").click()
self.driver.find_element_by_name("减").click()
self.driver.find_element_by_name("一").click()
self.driver.find_element_by_name("等于").click()
self.assertEqual(self.getresults(), "8")


if __name__ == '__main__':
unittest.main()

java(GitHub):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import java.util.concurrent.TimeUnit;
import java.net.URL;
import io.appium.java_client.windows.WindowsDriver;

import org.testng.Assert;
import org.testng.annotations.*;

public class WindowsCalculatorTest {

private static WindowsDriver CalculatorSession = null;
private static WebElement CalculatorResult = null;

@BeforeClass
public static void setup() {
try {
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("app", "Microsoft.WindowsCalculator_8wekyb3d8bbwe!App");
CalculatorSession = new WindowsDriver(new URL("http://127.0.0.1:4723"), capabilities);
CalculatorSession.manage().timeouts().implicitlyWait(2, TimeUnit.SECONDS);
CalculatorResult = CalculatorSession.findElementByAccessibilityId("CalculatorResults");

}catch(Exception e){
e.printStackTrace();
} finally {}
}

@AfterClass
public static void TearDown()
{
CalculatorResult = null;
if (CalculatorSession != null) {
CalculatorSession.quit();
}
CalculatorSession = null;
}

@Test
public void Addition()
{
CalculatorSession.findElementByName("七").click();
CalculatorSession.findElementByName("七").click();
CalculatorSession.findElementByName("加").click();
CalculatorSession.findElementByName("八").click();
CalculatorSession.findElementByName("等于").click();
Assert.assertEquals("显示为 85", CalculatorResult.getText());
}

@Test
public void Combination()
{
CalculatorSession.findElementByName("七").click();
CalculatorSession.findElementByName("乘以").click();
CalculatorSession.findElementByName("九").click();
CalculatorSession.findElementByName("加").click();
CalculatorSession.findElementByName("一").click();
CalculatorSession.findElementByName("等于").click();
CalculatorSession.findElementByName("除以").click();
CalculatorSession.findElementByName("八").click();
CalculatorSession.findElementByName("等于").click();
Assert.assertEquals("显示为 8", CalculatorResult.getText());
}

@Test
public void Division()
{
CalculatorSession.findElementByName("六").click();
CalculatorSession.findElementByName("四").click();
CalculatorSession.findElementByName("除以").click();
CalculatorSession.findElementByName("八").click();
CalculatorSession.findElementByName("等于").click();
Assert.assertEquals("显示为 8", CalculatorResult.getText());
}

@Test
public void Multiplication()
{
CalculatorSession.findElementByName("六").click();
CalculatorSession.findElementByName("乘以").click();
CalculatorSession.findElementByName("八").click();
CalculatorSession.findElementByName("等于").click();
Assert.assertEquals("显示为 48", CalculatorResult.getText());
}

@Test
public void Subtraction()
{
CalculatorSession.findElementByName("九").click();
CalculatorSession.findElementByName("减").click();
CalculatorSession.findElementByName("一").click();
CalculatorSession.findElementByName("等于").click();
Assert.assertEquals("显示为 8", CalculatorResult.getText());
}
}
参考
问题总结

org.openqa.selenium.WebDriverException: Failed to locate opened application window with appId

遇到此问题是在启动APP时报的错,成功的启动了APP,但是抛出这个异常,导致后续无法测试,目前找了一个临时解决方案:在new driver时增加try catch机制,即可避免,例如:

1
2
3
4
5
6
try {
driver = new WindowsDriver(new URL("http://127.0.0.1:4723"), cap);
}catch (Exception e){
// e.printStackTrace();
driver = new WindowsDriver(new URL("http://127.0.0.1:4723"), cap);
}
如果觉得本文对您有帮助,欢迎打赏,谢谢。