接下来要做的是与应用程序的不同元素进行交互,因此需要在交互之前首先定位元素。定位元素可以在AndroidDriver 实例本身上完成,因为它为我们提供了“ Find Element ”和“ Find Elements ”方法来定位Appium上的元素。在本章中,我们将学习如何使用FindElement和FindElements命令或如何使用具有不同属性的Appium UiAutomatorViewer / Appium Inspector定位元素。
如何在Appium中使用FindElement和FindElements方法
Find Element和Find Elements方法之间的区别是第一个返回WebElement对象,否则它会抛出异常而后者返回WebElements列表,如果没有DOM元素与查询匹配,它可以返回一个空列表。在查找方法采取定位器调用或查询对象通过。“ 按”策略列在下面。
按名字
这也是定位元素的有效方法,但问题与UI开发人员在页面上具有非唯一名称或自动生成名称的ID相同。使用此策略,将返回名称属性值与位置匹配的第一个元素。如果没有元素具有匹配的name属性,则将引发NoSuchElementException 。
示例1:如果给出的元素如下:
可以使用以下命令定位上述元素:
1 2 3 | driver.findElement(By.name("Shop byDepartment")).click(); //or driver.findElementByName("Shop byDepartment").click(); |
示例2:如果给出的元素如下:
可以使用以下命令定位上述元素:
1 2 | WebElement element = driver.findElement(By.name("Home")); element.click(); |
如何在Appium中使用' content-desc '属性查找元素?
content-desc属性可以与 findElementByName的text 属性完全一样使用。看下面的例子:
示例3:如果给出的元素如下:
可以使用以下命令定位上述元素:
1 | driver.findElementByName("Sign inHello. Link").click(); |
按类名
有了这个,你可以根据class属性的值找到元素。如果一个元素有很多类,那么这将匹配它们中的每一个。一个类可以包含许多元素。
示例:如果给出的元素如下:
可以使用以下命令定位上述元素:
1 2 3 4 |
driver.findElementByClassName("android.widget.ImageView").click(); //or driver.findElement(By.className("android.widget.ImageView")).click(); |
注意:只有当这是一个唯一的类名时才能有效地工作,这在Appium中通常不是这种情况。但是我们仍然可以将 className与其他结合使用,我们将在下面给出一个详细的例子。
按ID
使用此策略,将返回id属性值与位置匹配的第一个元素。如果没有元素具有匹配的id属性,则将引发NoSuchElementException 。这是定位元素的最有效和首选方式,因为大多数时间ID都是唯一的。
示例:如果给出的元素如下:
可以使用以下命令定位上述元素:
1 2 3 4 5 6 | WebElement element = driver.findElementById("in.amazon.mShop.android.shopping:id/action_bar_burger_icon");<br>element.click(); // or WebElement element = driver.findElement(By.id("in.amazon.mShop.android.shopping:id/action_bar_burger_icon"));<br>element.click(); element.click(); // or driver.findElementById("in.amazon.mShop.android.shopping:id/action_bar_burger_icon").click(); |
通过XPath
Xpath 在Appium中是一个真正的祝福,因为你会遇到许多情况,你没有任何选择,只能使用 xpath。Xpath可以是相对的和绝对的,但建议始终使用相对xpath。
让我们看一下Amazon Sign In模块的Password字段下面的示例。密码文本框没有附加任何ID,没有任何文本值和content-desc。但是,在这种情况下,我们的className填充但同样是没有帮助,因为类名的的用户名文本框也一样。
示例:如果给出了这样的元素
如果您检查' (5)查看{密码} [...] [...] ',您会注意到该元素的content-desc值为' Password '。这意味着我们可以使用属性content-desc轻松找到(5)元素,然后遍历到(6)元素,然后我们可以轻松地到达其子元素EditText。
要找到(5)元素,可以使用xpath:
1 | driver.findElementByXPath("//android.view.View[@content-desc='Password']"); |
如何在Xpath中使用兄弟姐妹
但是我们的场景说我们需要找到(6)元素的子元素。 因此,首先需要定位(6)哪个是(5)的兄弟。在Xpath中,有一种方法可以找到兄弟元素。下面的语句将找到(6)元素:
1 | driver.findElementByXPath("//android.view.View[@content-desc='Password']/following-sibling::android.view.View"); |
一旦我们达到(6)元素,很容易找到密码的文本字段是(6)的孩子,并且可以用这个来完成:
1 | driver.findElementByXPath("//android.view.View[@content-desc='Password']/following-sibling::android.view.View/android.widget.EditText"); |
完整的代码现在看起来像这样:
1 | driver.findElementByXPath("//android.view.View[@content-desc='Password']/following-sibling::android.view.View/android.widget.EditText").sendKeys("Lakshay"); |
如何使用父节点查找元素?
这也是在Appium中定位元素的一项非常重要的技术。在许多情况下,locate元素的唯一选择是首先获取父元素,然后获取其子对象以对子元素执行任何操作。
请考虑此方案的用户名文本框。UserName文本框没有附加任何ID,没有任何文本值和content-desc。但是,在这种情况下,我们的className填充但同样是没有帮助,因为类名的的密码文本框也一样“ android.widget.EditText ”。如果我们向EditText的父级迈进一步,那么它是一个View,其className为' android.view.View ',它同样不是唯一的。所以,我们需要再一步找到独特的父母,这是亚马逊登录如下图所示:
可以使用以下命令定位上述元素:
1 | WebElement parentElement = driver.findElement(By.name("Amazon Sign In")); |
使用上面的语句,我们将能够获取父元素,但我们对父元素的子元素感兴趣。使用以下语句,我们将获得所选父级下的所有子元素“ 视图”:
1 | List<WebElement> childElements = parentElement.findElements(By.className("android.view.View")); |
现在我们在childElements中有了所有的Views元素,但我们对第5个子元素感兴趣,因为用户名文本框位于第5个View元素下。请参阅以下屏幕截图以获取帮助
可以使用以下命令定位上述元素:
1 2 | //This is to get the 5th child element WebElement mainElement = childElements.get(4); |
注意:我们为第5个元素提到了.get(4),因为索引从零开始。
一旦我们得到主要元素(第5个),就很容易指出它的子元素:
1 | mainElement.findElements(By.className("android.widget.EditText")).sendKeys("Your_UserName"); |
完整的代码现在看起来像这样:
1 2 3 4 | WebElement parentElement = driver.findElement(By.name("Amazon Sign In")); List<WebElement> childElements = parentElement.findElements(By.className("android.view.View")); WebElement mainElement = childElements.get(4); mainElement.findElement(By.className("android.widget.EditText")).sendKeys("Your_USerName"); |
练习练习
1)启动Appium Node Server
2)启动Amazon App
3)使用By.ID单击“按部门购买”。
4)使用By.ClassName单击“菜单”按钮以显示菜单列表。
5)使用By.Name单击Home链接以导航回主屏幕。
6)使用By.Name单击SIgn In链接登录应用程序。
7)使用By.xpath和Sibling策略在UserName字段中输入文本
8)使用父节点策略在密码字段中输入文本
9)使用content-desc属性单击Submit按钮。
solution
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 | package amazon;
import io.appium.java_client.android.AndroidDriver;
import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.util.List; import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.CapabilityType; import org.openqa.selenium.remote.DesiredCapabilities;
public class Amazon_LogIn_Test { private static AndroidDriver driver;
public static void main(String[] args) throws MalformedURLException { File classpathRoot = new File(System.getProperty("user.dir")); File appDir = new File(classpathRoot, "/Apps/Amazon/"); File app = new File(appDir, "in.amazon.mShop.android.shopping.apk");
DesiredCapabilities capabilities = new DesiredCapabilities(); capabilities.setCapability(CapabilityType.BROWSER_NAME, ""); capabilities.setCapability("deviceName", "Micromax A311"); capabilities.setCapability("platformVersion", "4.4.2"); capabilities.setCapability("platformName", "Android"); capabilities.setCapability("app", app.getAbsolutePath()); capabilities.setCapability("appPackage", "in.amazon.mShop.android.shopping"); capabilities.setCapability("appActivity", "com.amazon.mShop.home.HomeActivity");
driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities); driver.manage().timeouts().implicitlyWait(80, TimeUnit.SECONDS);
// Click on Shop by Deparment link driver.findElementById("in.amazon.mShop.android.shopping:id/web_home_shop_by_department_label").click(); // Click on Main menu driver.findElementByClassName("android.widget.ImageView").click(); // Click on Home link under Main menu driver.findElement(By.name("Home")).click(); // Click on Sign In link on the Home Screen driver.findElementByName("Sign inHello. Link").click();
// Entering UserName using Parent node strategy WebElement parentElement = driver.findElement(By.name("Amazon Sign In")); List<WebElement> childElements = parentElement.findElements(By.className("android.view.View")); WebElement mainElement = childElements.get(4); mainElement.findElement(By.className("android.widget.EditText")).sendKeys("Your_UserName"); // Entering Password using Xpath & Sibling strategy driver.findElementByXPath("//android.view.View[@content-desc='Password']/following-sibling::android.view.View/android.widget.EditText").sendKeys("Your_Password"); // Click on Sign In button driver.findElement(By.name("Sign in")).click(); // This is to kill the Android driver driver.quit();
}
} |