Appium PageObject

原文地址http://blog.csdn.net/TalorSwfit20111208/article/details/77434950

由于无法联系上您,在此分享您的文章,希望谅解!

Appium PageObject 直接沿用了Selenium的PageObject设计模式,

PageObject主要优点如下:

一、将UI元素与逻辑分离方便后期维护

二、减少代码冗余

三、增强代码可读性

来看个例子

没有使用PO设计模式的代码如下:

[java] view plain copy
 
  1. @Test  
  2. public void twoPlusTwoOperation() {  
  3.   
  4.     /* 获取控件*/  
  5.     MobileElement buttonTwo = (MobileElement)(driver.findElement(By.id("net.ludeke.calculator:id/digit2")));  
  6.     MobileElement buttonPlus = (MobileElement)(driver.findElement(By.id("net.ludeke.calculator:id/plus")));  
  7.     MobileElement buttonEquals = (MobileElement)(driver.findElement(By.id("net.ludeke.calculator:id/equal")));  
  8.     MobileElement resultField = (MobileElement)(driver.findElement(By.xpath("//android.widget.EditText[1]")));  
  9.   
  10.     /* 计算2+2*/  
  11.     buttonTwo.click();  
  12.     buttonPlus.click();  
  13.     buttonTwo.click();  
  14.     buttonEquals.click();  
  15.   
  16.     /* 检查在给定的时间内是否显示要查找的控件 */  
  17.     new WebDriverWait(driver, 30).until(ExpectedConditions.textToBePresentInElement(resultField, EXPECTED_RESULT_FOUR));  
  18.   
  19. }  

使用了PO设计模式的代码如下

[java] view plain copy
 
  1. @Test  
  2. public void twoPlusTwoOperation() {  
  3.   
  4.     app.calculatorScreen().addTwoAndTwo();  
  5.     assertTrue(app.calculatorScreen().isResultCorrect("4"));  
  6.   
  7. }  

我们注意到的第一个最直接的变化是测试方法的长度。使用PageObject模式编写的测试方法几乎总是比原始的方法短(对于较长的测试而言更短)。如果你继续阅读,你会注意到,这不仅是因为我们在addTwoAndTwo方法中包装了所有的按钮。
可读性怎么样?再次通过这两种方法,问问自己在哪种情况下更容易理解发生了什么。另外,请注意我们如何在第二种方法中真的不需要注释,因为指定与Page Object具有的交互的方法具有重要的名称。
通过将低级操作包含在专用方法中,我们现在有了不直接引用任何WebDriver API的测试方法。在编写第一个PageObject测试方法时,请使用缺少引用低级API的导入语句作为根据模式进行处理的指标。
这种方法给了我们另一个不容忽视的优点:通过隐藏单一实用程序方法的技术复杂性,PageObject模式使得用户交互的流程变得明显。对于更长,更复杂的测试,以及我们编写测试的整个方式的转换,这特别有用。一旦实现了应用程序屏幕的基本交互,编写测试方法基本上只是通过调用正确名称所指的方法来复制用例。这就是为什么你应该努力为他们选择最好的名字。

PageObject控件定位

pageobject控件定位是使用注解方式来定位的,如下

# WebElement/列表 WebElement 字段可以这样定位:

使用@FindBy注解

[java] view plain copy
 
  1. import org.openqa.selenium.support.FindBy;  
  2. import org.openqa.selenium.WebElement;  
  3. @FindBy(someStrategy)//用来定位浏览器或者webview UI  
  4. //也可以用来定位native 应用,当没有定义其他定位策略时  
  5. WebElement someElement;@FindBy(someStrategy) //用来定位浏览器或者webview UI  
  6. //也可以用来定位native 应用,当没有定义其他定位策略时  
  7. List<WebElement> someElements;//定位包含相同控件属性的控件  

使用@AndroidFindBy来定位

[java] view plain copy
 
  1. import io.appium.java_client.android.AndroidElement;  
  2. import org.openqa.selenium.remote.RemoteWebElement;  
  3. import io.appium.java_client.pagefactory.*;  
  4.   
  5. @AndroidFindBy(someStrategy) //用Android UI Automator来定位Android UI  
  6. AndroidElement someElement;  
  7.   
  8. @AndroidFindBy(someStrategy) //用Android UI Automator来定位Android UI  
  9.   
  10. List<AndroidElement> someElements;  


多种组合查找策略

[java] view plain copy
 
  1. import org.openqa.selenium.remote.RemoteWebElement;  
  2. import io.appium.java_client.pagefactory.*;  
  3. import org.openqa.selenium.support.FindBy;  
  4. import org.openqa.selenium.support.FindByAll;  
  5.   
  6.   
  7. import static io.appium.java_client.pagefactory.LocatorGroupStrategy.ALL_POSSIBLE;  
  8.   
  9. @HowToUseLocators(androidAutomation = ALL_POSSIBLE, iOSAutomation = ALL_POSSIBLE)  
  10. @FindAll{@FindBy(someStrategy1), @FindBy(someStrategy2)})   
  11. @AndroidFindBy(someStrategy1) @AndroidFindBy(someStrategy2)   
  12. @iOSFindBy(someStrategy1) @iOSFindBy(someStrategy2)   
  13. RemoteWebElement someElement;  
  14.   
  15. @HowToUseLocators(androidAutomation = ALL_POSSIBLE, iOSAutomation = ALL_POSSIBLE)  
  16. @FindAll({@FindBy(someStrategy1), @FindBy(someStrategy2)})   
  17. @AndroidFindBy(someStrategy1) @AndroidFindBy(someStrategy2)  
  18. @iOSFindBy(someStrategy1) @iOSFindBy(someStrategy2)  
  19. List<RemoteWebElement> someElements;  


## 也可以用下面这种方式: 

[java] view plain copy
 
  1. import org.openqa.selenium.remote.RemoteWebElement;  
  2. import io.appium.java_client.pagefactory.*;  
  3. import org.openqa.selenium.support.FindBy;  
  4. import org.openqa.selenium.support.FindByAll;  
  5.   
  6. import static io.appium.java_client.pagefactory.LocatorGroupStrategy.CHAIN;  
  7. import static io.appium.java_client.pagefactory.LocatorGroupStrategy.ALL_POSSIBLE;  
  8.   
  9. @HowToUseLocators(androidAutomation = CHAIN, iOSAutomation = ALL_POSSIBLE)  
  10. @FindAll{@FindBy(someStrategy1), @FindBy(someStrategy2)})   
  11. @AndroidFindBy(someStrategy1) @AndroidFindBy(someStrategy2)   
  12. @iOSFindBy(someStrategy1) @iOSFindBy(someStrategy2)   
  13. RemoteWebElement someElement;  
  14.   
  15. @HowToUseLocators(androidAutomation = CHAIN, iOSAutomation = ALL_POSSIBLE)  
  16. @FindAll({@FindBy(someStrategy1), @FindBy(someStrategy2)})   
  17. @AndroidFindBy(someStrategy1) @AndroidFindBy(someStrategy2)  
  18. @iOSFindBy(someStrategy1) @iOSFindBy(someStrategy2)  
  19. List<RemoteWebElement> someElements;  


或者

[java] view plain copy
 
  1. import org.openqa.selenium.remote.RemoteWebElement;  
  2. import io.appium.java_client.pagefactory.*;  
  3. import org.openqa.selenium.support.FindBy;  
  4. import org.openqa.selenium.support.FindByAll;  
  5.   
  6. import static io.appium.java_client.pagefactory.LocatorGroupStrategy.ALL_POSSIBLE;  
  7.   
  8. @HowToUseLocators(iOSAutomation = ALL_POSSIBLE)  
  9. @FindAll{@FindBy(someStrategy1), @FindBy(someStrategy2)})   
  10. @AndroidFindBy(someStrategy1) @AndroidFindBy(someStrategy2) //this is the chain   
  11. //by default  
  12. @iOSFindBy(someStrategy1) @iOSFindBy(someStrategy2)   
  13. RemoteWebElement someElement;  
  14.   
  15. @HowToUseLocators(iOSAutomation = ALL_POSSIBLE)  
  16. @FindAll({@FindBy(someStrategy1), @FindBy(someStrategy2)})   
  17. @AndroidFindBy(someStrategy1) @AndroidFindBy(someStrategy2) //this is the chain   
  18. //by default  
  19. @iOSFindBy(someStrategy1) @iOSFindBy(someStrategy2)  
  20. List<RemoteWebElement> someElements;  

应用PO查找

# Appium Java client使用了AppiumFieldDecorator来融合了Selenium PageFactory 

对象字段结构如下: 

[java] view plain copy
 
  1. import io.appium.java_client.pagefactory.*;  
  2. import org.openqa.selenium.support.PageFactory;  
  3.   
  4. PageFactory.initElements(new AppiumFieldDecorator(searchContext   
  5.               /*searchContext is a WebDriver or WebElement 
  6.               instance */),   
  7.               pageObject //对象类的一个实例  
  8. );  
[java] view plain copy
 
  1. import io.appium.java_client.pagefactory.*;  
  2. import org.openqa.selenium.support.PageFactory;  
  3. import java.util.concurrent.TimeUnit;  
  4.   
  5. PageFactory.initElements(new AppiumFieldDecorator(searchContext,   
  6.               /*searchContext is a WebDriver or WebElement 
  7.               instance */  
  8.         15, //默认为所有查找策略的隐式等待时间  
  9.         TimeUnit.SECONDS),   
  10.             pageObject //对象类的一个实例  
  11.   
  12. );  
[java] view plain copy
 
  1. import io.appium.java_client.pagefactory.*;  
  2. import org.openqa.selenium.support.PageFactory;  
  3. import java.util.concurrent.TimeUnit;  
  4.   
  5. PageFactory.initElements(new AppiumFieldDecorator(searchContext,   
  6.               /*searchContext is a WebDriver or WebElement 
  7.               instance */  
  8.         new TimeOutDuration(15, //默认为所有查找策略的隐式等待时间  
  9.   
  10.         TimeUnit.SECONDS)),   
  11.             pageObject //对象类的一个实例  
  12.   
  13. );  


来看个经典计算器程序在PageObject中的实际应用

项目结构
安装程序的核心组件将是以下类:

  • AbstractTest:我们在其中设置测试阶段;
  • AppiumDriverBuilder:设置所需的功能并实例化驱动程序;
  • 我们调用的应用程序类访问我们的Screen对象;
  • AbstractScreen,包含您的Screen对象之间的所有共享方法;
  • Screen类包含表示用户与被测试应用程序交互的方法;
  • 测试类包含一个或多个测试,写成屏幕方法调用序列。

为了进一步澄清项目结构,您可以将这些类组织成包。在一个实用程序包中,您可以包括您的AppiumDriverBuilder类以及您创建的其他实用程序类。您也可以将AbstractScreen类和其他Screen类放在屏幕包中。项目结构如下:


AbstractTest
在项目的中心是AbstractTest类。这里我们定义我们的测试套件方法,它将在每次测试运行之前执行。这里我们做两件非常重要的事情:

  1. 负责初始化负责连接到Appium服务器的驱动程序;
  2. 实例化了App类,这将允许我们访问我们想要测试的应用程序的单个屏幕;
[java] view plain copy
 
  1. package com.test.calculatortest;  
  2.   
  3. import com.test.calculatortest.Calculator;  
  4. import com.test.calculatortest.util.AppiumDriverBuilder;  
  5.   
  6. import io.appium.java_client.AppiumDriver;  
  7.   
  8. import org.junit.Before;  
  9.   
  10. import java.net.MalformedURLException;  
  11. import java.net.URL;  
  12.   
  13. public abstract class AbstractTest {  
  14.   
  15.     private AppiumDriver<?> driver;  
  16.     protected Calculator app;  
  17.   
  18.     /* Establish a connection to TestObject, or to a local device test is local. */  
  19.     @Before  
  20.     public void connect() throws MalformedURLException {  
  21.   
  22.         this.driver = AppiumDriverBuilder.forAndroid()  
  23.                 .withEndpoint(new URL("http://127.0.0.1:4723/wd/hub"))  
  24.                 .build("com.android.calculator2", ".Calculator");  
  25.         //实例化应用类  
  26.         app = new Calculator(driver);  
  27.   
  28.     }  
  29.   
  30. }  

AppiumDriverBuilder
它基本上是一个支持类,负责配置和实例化的Appium驱动程序。

[java] view plain copy
 
  1. package com.test.calculatortest.util;  
  2.   
  3. import io.appium.java_client.AppiumDriver;  
  4. import io.appium.java_client.android.AndroidDriver;  
  5. import io.appium.java_client.android.AndroidElement;  
  6.   
  7. import org.openqa.selenium.remote.DesiredCapabilities;  
  8.   
  9. import java.net.URL;  
  10.   
  11. public abstract class AppiumDriverBuilder<SELF, DRIVER extends AppiumDriver<?>> {  
  12.   
  13.   
  14.   
  15.     public static AndroidDriverBuilder forAndroid() {  
  16.         return new AndroidDriverBuilder();  
  17.     }  
  18.   
  19.     public static class AndroidDriverBuilder extends AppiumDriverBuilder<AndroidDriverBuilder, AndroidDriver<?>> {  
  20.   
  21.         DesiredCapabilities capabilities = new DesiredCapabilities();  
  22.   
  23.         @Override  
  24.         public AndroidDriver<?> build(String appPackage,String appActivity) {  
  25.   
  26.               
  27.               
  28.               
  29.             capabilities.setCapability("platformName", "Android");  
  30.             //使用Android模拟器  
  31.             capabilities.setCapability("deviceName", "testDevice");  
  32.             //使用Android模拟器  
  33.             capabilities.setCapability("platformVersion", "4.4.4");  
  34.             //不重新安装应用  
  35.             capabilities.setCapability("noReset",true);  
  36.             //待测包名及首次启动的页面  
  37.             capabilities.setCapability("appPackage", appPackage);  
  38.             capabilities.setCapability("appActivity", appActivity);  
  39.             //使用appium Unicode键盘输入法,输入完毕后重置输入法  
  40.             capabilities.setCapability("unicodeKeyboard", true);  
  41.             capabilities.setCapability("resetKeyboard", true);  
  42.               
  43.             capabilities.setCapability("deviceReadyTimeout",30);  
  44.   
  45.             return new AndroidDriver<AndroidElement>(endpoint, capabilities);  
  46.   
  47.         }  
  48.   
  49.       
  50.   
  51.     }  
  52.   
  53.     protected URL endpoint;  
  54.   
  55.     @SuppressWarnings("unchecked")  
  56.     public SELF withEndpoint(URL endpoint) {  
  57.         this.endpoint = endpoint;  
  58.   
  59.         return (SELF) this;  
  60.     }  
  61.   
  62.     public abstract DRIVER build(String appPackage,String appActivity);  
  63.   
  64. }  

应用类
测试中的另一个中心类将是Application类(我们简单的命名为我们正在测试的应用程序的名称)。这个类的功能是提供屏幕(正如我们之前所说的,Page对象)到需要访问它们的功能的方法(屏幕类中的测试方法)。

[java] view plain copy
 
  1. package com.test.calculatortest;  
  2.   
  3.   
  4. import com.test.calculatortest.screen.CalculatorScreen;  
  5.   
  6.   
  7. import io.appium.java_client.AppiumDriver;  
  8. /* 
  9.  * 应用类,返回各个操作页面类 
  10.  */  
  11. public class Calculator {  
  12.   
  13.   
  14.     private final AppiumDriver<?> driver;  
  15.   
  16.   
  17.     public Calculator(AppiumDriver<?> driver) {  
  18.         this.driver = driver;  
  19.     }  
  20.   
  21.   
  22.     public CalculatorScreen calculatorScreen() {  
  23.         return new CalculatorScreen(driver);  
  24.     }  
  25.   
  26.   
  27. }  

AbstractScreen类

AbstractScreen类将包含Screen对象之间共享的所有方法。这些可能是通用目的的方法,可以执行多个点(滑动,滚动)与应用程序交互所需的手势,这些手段隐藏了一些更为复杂的代码,从而增加了测试方法的可读性,同步方法等。

[java] view plain copy
 
  1. package com.test.calculatortest.screen;  
  2.   
  3. import io.appium.java_client.AppiumDriver;  
  4. import io.appium.java_client.MobileElement;  
  5. import io.appium.java_client.pagefactory.AppiumFieldDecorator;  
  6. import org.openqa.selenium.By;  
  7. import org.openqa.selenium.OutputType;  
  8. import org.openqa.selenium.support.PageFactory;  
  9. import org.openqa.selenium.support.ui.ExpectedConditions;  
  10. import org.openqa.selenium.support.ui.WebDriverWait;  
  11.   
  12. public abstract class AbstractScreen {  
  13.   
  14.     protected final AppiumDriver<?> driver;  
  15.   
  16.     public AbstractScreen(AppiumDriver<?> driver) {  
  17.         this.driver = driver;  
  18.   
  19.         PageFactory.initElements(new AppiumFieldDecorator(driver), this);  
  20. }  
  21.   
  22.     public MobileElement findElementWithTimeout(By by, int timeOutInSeconds) {  
  23.         return (MobileElement)(new WebDriverWait(driver, timeOutInSeconds)).until(ExpectedConditions.presenceOfElementLocated(by));  
  24.     }  
  25.   
  26.     protected void takeScreenShot(){  
  27.         driver.getScreenshotAs(OutputType.BASE64);  
  28.     }  
  29.   
  30. }  

注意
PageFactory.initElements(new AppiumFieldDecorator(driver), this);这句,这可以让你使用注释来抓取UI元素,因此请勿忘记将其包含在您的设置中!

屏幕类
屏幕类代表应用程序的屏幕。在这里获取UI元素并与代表可能与用户界面交互的方法与其进行交互,例如打开菜单并选择项目,填写某些字段并按下提交按钮,向下滚动列表并选择正确的元素这样,你的测试方法将只是不同屏幕上的一系列用户交互。这将使你的测试易于维护和扩展。

[java] view plain copy
 
  1. package com.test.calculatortest.screen;  
  2.   
  3. import io.appium.java_client.AppiumDriver;  
  4. import io.appium.java_client.MobileElement;  
  5. import io.appium.java_client.pagefactory.AndroidFindBy;  
  6. import org.openqa.selenium.TimeoutException;  
  7. import org.openqa.selenium.support.ui.ExpectedConditions;  
  8. import org.openqa.selenium.support.ui.WebDriverWait;  
  9.   
  10. public class CalculatorScreen extends AbstractScreen {  
  11.   
  12.     @AndroidFindBy(id = "com.android.calculator2:id/digit2")  
  13.     private MobileElement buttonTwo;  
  14.   
  15.     @AndroidFindBy(id = "com.android.calculator2:id/plus")  
  16.     private MobileElement buttonPlus;  
  17.   
  18.     @AndroidFindBy(id = "com.android.calculator2:id/equal")  
  19.     private MobileElement buttonEquals;  
  20.   
  21.     @AndroidFindBy(xpath = "//android.widget.EditText[1]")  
  22.     private MobileElement resultField;  
  23.   
  24.     public CalculatorScreen(AppiumDriver<?> driver) {  
  25.         super(driver);  
  26.     }  
  27.   
  28.     public void addTwoAndTwo() {  
  29.   
  30.         buttonTwo.click();  
  31.         buttonPlus.click();  
  32.         buttonTwo.click();  
  33.         buttonEquals.click();  
  34.   
  35.     }  
  36.   
  37.     public boolean isResultCorrect(String result) {  
  38.   
  39.         try {  
  40.   
  41.             /* Check if within given time the correct result appears in the designated field. */  
  42.             (new WebDriverWait(driver, 30)).until(ExpectedConditions.textToBePresentInElement(resultField, result));  
  43.             return true;  
  44.   
  45.         } catch (TimeoutException e) {  
  46.   
  47.             return false;  
  48.   
  49.         }  
  50.   
  51.     }  
  52.   
  53. }  

除了刚刚描述的应用程序的显着“主屏幕”之外,我们还可以创建另一个表示计算器应用程序的“高级面板”的程序,这基本上是自己的屏幕。在此屏幕中引用的UI元素将是计算器的符号/函数。
你可以为应用程序的每个屏幕创建一个Screen对象,也可以决定仅对真正重要的屏幕执行此操作。这两种方法都有其优点和缺点,但请记住,可以使用太多屏幕的应用程序来处理,另一方面,在一个Screen对象中抽取太多的屏幕可能会导致混乱。
测试类
您的测试按照扩展AbstractTest的类进行分组。这允许您抓住应用程序的任何屏幕,并通过您编写的方法与其进行交互。

[java] view plain copy
 
  1. package com.test.calculatortest;  
  2.   
  3.   
  4. import org.junit.Test;  
  5.   
  6.   
  7. import static org.junit.Assert.assertTrue;  
  8. /* 
  9.  *  
  10.  * 逻辑操作类 
  11.  * 
  12.  */  
  13. public class OperationTests extends AbstractTest {  
  14.   
  15.   
  16.     public OperationTests() {}  
  17.   
  18.   
  19.     /* 一个简单的加法运算,期望结果为正确的值 */  
  20.     @Test  
  21.     public void twoPlusTwoOperation() {  
  22.   
  23.   
  24.         app.calculatorScreen().addTwoAndTwo();  
  25.         assertTrue(app.calculatorScreen().isResultCorrect("4"));  
  26.   
  27.   
  28.     }  
  29.   
  30.   
  31. }  

将计算器的例子放在一边,并跳入一个现实世界的例子:

[java] view plain copy
 
  1. public class ChatTest extends AbstractTest {  
  2.     @Test  
  3.         public void sendMessageAndCheckHistoryTest() {  
  4.   
  5.             login(Credentials.VALID_USER_CREDENTIALS);  
  6.   
  7.              app.mainScreen().startChatWithUser(TEST_USERNAME);  
  8.   
  9.             app.chatScreen().sendChatMessage(TEST_MESSAGE);  
  10.   
  11.             app.chatScreen().navigateToHistoryScreen();  
  12.             assertTrue(app.historyScreen().containsMessage(TEST_MESSAGE));  
  13.   
  14.         }  
  15.   
  16.   
  17.         @Test  
  18.         public void sendAndDeleteMessageThenCheckHistoryTest() {  
  19.   
  20.   
  21.             ...  
  22.   
  23.   
  24.         }         
  25.   
  26.   
  27. }  

正如你所看到的,当涉及多个屏幕时,这种模式的目的变得清晰,方便起见。我们现在正在浏览我们从未见过的一系列屏幕,但是我们已经可以得到我们测试中发生了什么的一般概念。如果我们看看我们调用的屏幕方法的实现,我们将会更准确地了解发生了什么。事实上,我们可以在没有这样做的情况下收集一些信息是使用PageObject编写测试的好处之一。
如果UI发生小的变化,我们可能不需要改动我们的测试方法:改动将在我们的屏幕方法之一发生。在这种变化频繁的敏捷环境中,除了测试脚本的强大性外,还特别受欢迎。
您可以选择自己的屏幕方法的复杂程度。拥有更多,更简单的屏幕方法将导致更长,更详细的测试方法,暴露更多的交互的复杂性。按照这种方法,上述方法看起来更像这样:

[java] view plain copy
 
  1. @Test  
  2. public void sendMessageAndCheckHistoryTest() {  
  3.   
  4.     login(Credentials.VALID_USER_CREDENTIALS);  
  5.   
  6.     app.mainScreen().navigateToUserSelection();  
  7.   
  8.     app.userSelectionScreen().selectUser(TEST_USERNAME);  
  9.   
  10.     app.userProfileScreen().startChat();  
  11.   
  12.     app.chatScreen().sendChatMessage(TEST_MESSAGE);  
  13.     app.chatScreen().navigateToMainScreen();  
  14.   
  15.     app.mainScreen().navigateToHistoryScreen();  
  16.   
  17.     assertTrue(app.historyScreen().containsMessage(TEST_MESSAGE));  
  18.   
  19.   
  20.   
  21.   
  22. }  

虽然这种方法显示了屏幕之间的每个过渡,但是它可能很容易成为压倒性的,如在这个例子中:

[java] view plain copy
 
  1. public class CreateDocumentationWithSuggestionTest extends AbstractTest {  
  2.   
  3.     @Test  
  4.     public void buildNewDocumentationWithSuggestions() {  
  5.   
  6.         app.documentationScreen().navigateToSettings();  
  7.         app.settingsScreen().navigateToSuggestions();  
  8.         app.settingsScreen().activateSuggestions(SUGGESTIONS));  
  9.         app.settingsScreen().navigateToDocumentation();  
  10.         app.documentationScreen().createDocumentation();  
  11.         app.documentationCreationScreen().selectCultivation();  
  12.         app.documentationDetailsScreen().selectFields(TEST_CULTIVATION_1.getFields());  
  13.         app.documentationDetailsScreen().selectConsumables(TEST_CULTIVATION_1.getConsumables());  
  14.         app.documentationDetailsScreen().selectWorkers(TEST_CULTIVATION_1.getWorkers());  
  15.         app.documentationDetailsScreen().sendActivity();  
  16.         app.documentationScreen().createDocumentation();  
  17.         app.documentationCreationScreen().selectCultivation();  
  18.         Assert.assertTrue(app.documentationDetailsScreen().areSuggestedFieldsFilledOut(TEST_CULTIVATION_1));  
  19.   
  20.     }  
  21.     ...  
  22.   
  23. }  

您应该保持测试方法足够短,以便您能够一目了然地告诉他们做什么,而不用将所有内容都包装到单一屏幕方法中。寻找平衡是编写一个好的,可维护的测试套件的关键。
总结:
PageObject前期可能工作量有点多,但是后面都是照葫芦画瓢非常容易维护,所以使用起来性价比还是挺高的,相比直来直去的测试脚本也减少了大量的重复代码

原文地址:https://www.cnblogs.com/111testing/p/8373335.html