2016-11-28 76 views
0

在我的團隊中,我們使用Appium和Appium Java-Client進行跨平臺UI測試。 我們的項目目前的結構是一樣的東西:Appium PageObject - 何時/何處實例化頁面?

mobile 
    pages 
    SignInPage 
    steps 
    SignInSteps 

的步驟是「粘」在一起使用Cucuember。 SignInPage看起來是這樣的:

public class SignInPage { 

    public SignInPage(AppiumDriver driver) { 
     PageFactory.initElements(new AppiumFieldDecorator(driver, 15, TimeUnit.SECONDS), this); 
    } 

    // region Identifiers 
    final String IOS_USERNAME_FIELD = "SignInUsernameField"; 
    final String ANDROID_USERNAME_FIELD = "new UiSelector().resourceIdMatches(\".*id/username.*\")"; 
    final String IOS_PASSWORD_FIELD = "SignInPasswordField"; 
    final String ANDROID_PASSWORD_FIELD = "new UiSelector().resourceIdMatches(\".*id/password_editText.*\")"; 
    final String IOS_SIGN_IN_BUTTON = "SignInButton"; 
    final String ANDROID_SIGN_IN_BUTTON = "new UiSelector().resourceIdMatches(\".*id/signInButton.*\")"; 
    // endregion 

    @iOSFindBy(accessibility = IOS_USERNAME_FIELD) 
    @AndroidFindBy(uiAutomator = ANDROID_USERNAME_FIELD) 
    private MobileElement usernameField; 

    @iOSFindBy(accessibility = IOS_PASSWORD_FIELD) 
    @AndroidFindBy(uiAutomator = ANDROID_PASSWORD_FIELD) 
    private MobileElement passwordField; 

    @iOSFindBy(accessibility = IOS_SIGN_IN_BUTTON) 
    @AndroidFindBy(uiAutomator = ANDROID_SIGN_IN_BUTTON) 
    private MobileElement signInButton; 

    public MobileElement getUsernameField() { 
     return usernameField; 
    } 

    public MobileElement getPasswordField() { 
     return passwordField; 
    } 

    public MobileElement getSignInButton() { 
     return signInButton; 
    } 

    public void tapUsernameField() { 
     getUsernameField().click(); 
    } 

    public void tapSignInButton() { 
     getSignInButton().click(); 
    } 

    public void clearUsernameEditText() { 
     getUsernameField().clear(); 
    } 
} 

我們不知道在性能和元素的查找方面是哪裏最好創建SignInPage的一個實例。目前我們的SignInSteps中有一個@Before方法,它在每個Gherkin場景開始之前執行(這不是理想的),但它有助於我們在SignInSteps類中有一個SignInPage屬性,它可以被所有步驟重用。

public class SignInSteps { 

    private SignInPage signInPage; 
    AppiumDriver driver; 

    @Before() 
    public void setUp() throws MalformedURLException { 
     driver = TestBase.getInstance().getDriver(); 
     signInPage = new SignInPage(driver); 
    } 

    @Given("I fill in the username and password") 
    public void fill_username_and_password() throws Throwable { 
     signInPage.tapUsernameField(); 
     signInPage.clearUsernameEditText(); 
     fillEditText(signInPage.getUsernameField(), PropertiesManager.getInstance().getValueForKey(Constants.SIGN_IN_USERNAME)); 
     fillEditText(signInPage.getPasswordField(), PropertiesManager.getInstance().getValueForKey(Constants.SIGN_IN_PASSWORD)); 
    } 
    // Other sign in steps below 
} 

但我覺得更簡潔的方法是在SignInSteps中的每個步驟方法內創建SignInPage作爲局部變量。在創建每個步驟中需要的頁面時,是否有任何性能影響?

此外,我還不清楚,用我們目前的方法(@Before方法),爲什麼它甚至在您爲稍後將要執行的某些步驟創建頁面時仍然工作(因此屏幕甚至不可見在此刻)。

所以也許更大的問題是如何查找元素?它調用PageFactory.initElements(新的AppiumFieldDecorator(驅動程序,15,TimeUnit.SECONDS),這個);或者實際訪問註釋的屬性時(這可能是某種我從Java的知識中沒有的懶惰初始化方法,除非我對Java註釋的理解是錯誤的)。

對不起,很長的文章,但這些是我想徹底理解的一些事情。所以任何幫助,高度讚賞。

謝謝!

回答

0

我做了一些更多的研究(調試),我已經找到了答案:通過反射(見AppiumFieldDecorator)與代理

當你調用PageFactory.initElements(new AppiumFieldDecorator(driver, 15, TimeUnit.SECONDS), this);從頁註釋屬性設置(裝飾)(ElementInterceptor )包裝MobileElement。每次您在註釋屬性上調用方法時,都會調用查找元素並轉發方法調用的代理。中間沒有緩存(與WidgetInterceptor相反,我還沒有弄清楚它在哪裏使用)。

所以在我的情況下,創建頁面一次或每一步並沒有真正有所作爲,因爲每次與它進行交互時都會執行元素查找(我認爲這很好,但它可能會有性能影響也)。

我還附上下面幾張截圖:

堆棧跟蹤,當你調用PageFactory.initElements(新AppiumFieldDecorator(驅動程序,15,TIMEUNIT。SECONDS),這個);

enter image description here

enter image description here

堆棧跟蹤,當你一個元素霍普

enter image description here

enter image description here

調用click這有助於其他人也瞭解該工具的工作。