博客首發
前提條件
- Windows 10或者更新版本
- 需要WinAppDriver
環境搭建
-
打開Windows PC的開發者模式
-
下載Windows SDK並默認安裝
-
下載Windows driver並默認安裝
-
運行
WinAppDriver.exe
(記得要用admin權限運行), 默認路徑 (C:\Program Files (x86)\Windows Application Driver
)
可以自定義地址或端口:WinAppDriver.exe 4727 WinAppDriver.exe 127.0.0.1 4725 WinAppDriver.exe 127.0.0.1 4723/wd/hub
如下圖:
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樣例代碼:
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樣例代碼:
// 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.exe
(C:\Program Files (x86)\Windows Kits\10\bin\x86
或者C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\x64
根據系統查看)來定位,詳情查看inspect,或者使用AccExplorer32、UISpy定位。
支持的定位方式:
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):
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):
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());
}
}
參考
- http://appium.io/docs/en/drivers/windows/
- https://github.com/Microsoft/WinAppDriver?WT.mc_id=-blog-scottha
問題總結
org.openqa.selenium.WebDriverException: Failed to locate opened application window with appId
遇到此問題是在啓動APP時報的錯,成功的啓動了APP,但是拋出這個異常,導致後續無法測試,目前找了一個臨時解決方案:在new driver
時增加try catch
機制,即可避免,例如:
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);
}