Hey there, fellow testers and automation enthusiasts! 👋 Are you tired of maintaining a messy codebase for your mobile test automation projects? Well, I've got just the thing for you – the Page Object Model (POM) with Appium! In this blog post, we'll dive deep into this powerful design pattern and see how it can revolutionize your mobile testing efforts.
Before we jump into the nitty-gritty, let's quickly recap what the Page Object Model is all about. POM is a design pattern that creates a separate object for each screen or page in your application. These objects encapsulate the page's elements and behaviors, making your tests more modular, easier to maintain, and less prone to breaking when the UI changes.
You might be wondering, "Why should I bother with POM for mobile testing?" Well, my friend, here are some compelling reasons:
Now that we're on the same page (pun intended), let's dive into implementing POM with Appium!
First things first, make sure you have Appium set up and ready to go. If you need help with that, check out the official Appium documentation. For this example, we'll be using Java, but the concepts apply to other languages too.
Let's create a simple project structure:
src
├── main
│ └── java
│ └── pages
│ ├── BasePage.java
│ ├── LoginPage.java
│ └── HomePage.java
└── test
└── java
└── tests
└── LoginTest.java
We'll start by creating a BasePage
class that all our page objects will inherit from:
package pages; import io.appium.java_client.AppiumDriver; import io.appium.java_client.pagefactory.AppiumFieldDecorator; import org.openqa.selenium.support.PageFactory; public class BasePage { protected AppiumDriver driver; public BasePage(AppiumDriver driver) { this.driver = driver; PageFactory.initElements(new AppiumFieldDecorator(driver), this); } }
This base class initializes the page factory, which helps us use the @AndroidFindBy
and @iOSXCUITFindBy
annotations for element locators.
Now, let's create our LoginPage
object:
package pages; import io.appium.java_client.AppiumDriver; import io.appium.java_client.pagefactory.AndroidFindBy; import io.appium.java_client.pagefactory.iOSXCUITFindBy; import org.openqa.selenium.WebElement; public class LoginPage extends BasePage { @AndroidFindBy(id = "username_input") @iOSXCUITFindBy(accessibility = "username_input") private WebElement usernameInput; @AndroidFindBy(id = "password_input") @iOSXCUITFindBy(accessibility = "password_input") private WebElement passwordInput; @AndroidFindBy(id = "login_button") @iOSXCUITFindBy(accessibility = "login_button") private WebElement loginButton; public LoginPage(AppiumDriver driver) { super(driver); } public void enterUsername(String username) { usernameInput.sendKeys(username); } public void enterPassword(String password) { passwordInput.sendKeys(password); } public void tapLoginButton() { loginButton.click(); } public void login(String username, String password) { enterUsername(username); enterPassword(password); tapLoginButton(); } }
Here, we've defined our page elements using Appium's cross-platform locator strategy. We've also created methods that represent actions a user can take on this page.
Now that we have our page object, let's write a test that uses it:
package tests; import io.appium.java_client.AppiumDriver; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import pages.LoginPage; import pages.HomePage; public class LoginTest { private AppiumDriver driver; private LoginPage loginPage; private HomePage homePage; @BeforeClass public void setUp() { // Initialize your AppiumDriver here loginPage = new LoginPage(driver); homePage = new HomePage(driver); } @Test public void testSuccessfulLogin() { loginPage.login("testuser", "password123"); Assert.assertTrue(homePage.isDisplayed(), "Login failed: Home page not displayed"); } }
Isn't that clean and readable? 😍 Our test focuses on the business logic rather than the implementation details.
Keep it DRY: Don't Repeat Yourself! If you find yourself copying code between page objects, consider moving it to the base class.
Use meaningful names: Name your methods based on what they do from a user's perspective, not how they do it.
Handle waits in page objects: Implement smart waits in your page objects to make your tests more robust.
Use enums for test data: Instead of hardcoding test data, use enums to make your tests more maintainable.
Implement logging: Add logging to your page objects to make debugging easier.
One of the great things about Appium is its cross-platform support. Here's a tip for handling platform-specific elements:
public WebElement getPlatformElement() { if (driver.getPlatformName().equalsIgnoreCase("Android")) { return androidElement; } else { return iosElement; } }
This way, you can have a single method that works for both platforms!
Phew! We've covered a lot of ground today. Implementing the Page Object Model with Appium might seem like extra work at first, but trust me, it's worth it in the long run. Your future self (and your team) will thank you for creating a maintainable and scalable test automation framework.
18/09/2024 | Mobile Testing
30/09/2024 | Mobile Testing
18/09/2024 | Mobile Testing
21/09/2024 | Mobile Testing
30/09/2024 | Mobile Testing
30/09/2024 | Mobile Testing
21/09/2024 | Mobile Testing
30/09/2024 | Mobile Testing
30/09/2024 | Mobile Testing