Appium PageObject - Kapan/Di mana membuat instance halaman?

Di tim saya, kami melakukan pengujian UI lintas platform menggunakan Appium dan Appium Java-Client. Struktur proyek kami saat ini adalah seperti:

mobile
   pages
     SignInPage
   steps
     SignInSteps

Langkah-langkahnya “direkatkan” dengan menggunakan Cucuember. SignInPage terlihat seperti ini:

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();
    }
}

Kami tidak yakin dalam hal kinerja dan pencarian elemen di mana cara terbaik untuk membuat instance SignInPage. Saat ini kami memiliki metode @Before di SignInSteps kami yang dijalankan sebelum setiap skenario Gherkin dimulai (yang tidak ideal) tetapi ini membantu kami memiliki properti SignInPage di kelas SignInSteps yang digunakan kembali oleh semua langkah.

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
}

Namun saya merasa pendekatan yang lebih bersih adalah dengan membuat SignInPage sebagai variabel lokal di dalam setiap metode langkah di SignInSteps. Apakah ada dampak kinerja dalam pembuatan halaman yang Anda perlukan di setiap langkah?

Selain itu, tidak jelas bagi saya, dengan pendekatan kami saat ini (pendekatan @Before) mengapa sebenarnya ini berfungsi bahkan ketika Anda membuat halaman untuk beberapa langkah yang akan dijalankan nanti (sehingga layar bahkan tidak terlihat pada saat ini) .

Jadi mungkin pertanyaan yang lebih besar adalah bagaimana elemen-elemennya dicari? Apakah saat memanggil PageFactory.initElements(new AppiumFieldDecorator(driver, 15, TimeUnit.SECONDS), this); atau ketika benar-benar mengakses properti beranotasi (yang merupakan semacam pendekatan inisialisasi malas yang menurut pengetahuan saya tidak dimiliki Java, kecuali pemahaman saya tentang anotasi Java salah).

Maaf postingannya panjang, tapi ini beberapa hal yang ingin saya pahami secara menyeluruh. Jadi bantuan apa pun sangat dihargai.

Terima kasih!


person Cosmin    schedule 28.11.2016    source sumber


Jawaban (1)


Saya melakukan penelitian lebih lanjut (debugging) dan saya menemukan jawabannya:

Saat Anda memanggil PageFactory.initElements(new AppiumFieldDecorator(driver, 15, TimeUnit.SECONDS), this);, properti beranotasi dari halaman disetel (dihiasi) melalui refleksi (lihat AppiumFieldDecorator) dengan proxy (ElementInterceptor) yang membungkus MobileElement. Setiap kali Anda memanggil metode pada properti beranotasi, Anda sebenarnya memanggil proxy yang mencari elemen dan meneruskan pemanggilan metode tersebut. Tidak ada cache di antaranya (berbeda dengan WidgetInterceptor yang saya belum tahu di mana ia digunakan).

Jadi dalam kasus saya, membuat halaman sekali, atau di setiap langkah tidak terlalu membuat perbedaan karena pencarian elemen dilakukan setiap kali Anda berinteraksi dengannya (yang menurut saya bagus, tetapi mungkin juga berdampak pada kinerja).

Saya juga melampirkan beberapa tangkapan layar di bawah ini:

Stacktrace saat Anda memanggil PageFactory.initElements(new AppiumFieldDecorator(driver, 15, TimeUnit.SECONDS), this);

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

Stacktrace saat Anda memanggil click pada sebuah elemen

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

Semoga ini bisa membantu orang lain juga memahami cara kerja alat ini.

person Cosmin    schedule 04.12.2016