In my test class, I have DesiredCapabilities
set up for Appium test. In that class, I initialised my BasePage class holding pagefactory
elements. When I run the test, it works as expected.
Now, I tried to be a bit more creative by moving my DediredCapabilities into a separate class, CapacityManager
. In my test class, I called the method holding the DesiredCapabilities from the CapacityManager. The method call was successful, my app was launched, but the pagefactory
elements were no longer working. I am not sure why.
When I run the test, I get a nullPointerExceptio on the first mobile element and this makes me suspect that a pagefactory
or driver initialisation problem.
The working test class looks like this:
public class LoginTest {
private final BaseUtil baseUtil = new BaseUtil();
private static BasePage basePage;
public static AndroidDriver<AndroidElement> driver;
public static File classpathRoot;
public void startApp() throws MalformedURLException {
classpathRoot = new File(System.getProperty("user.dir"));
File appDir = new File(classpathRoot, "");
File app = new File(appDir, baseUtil.getMyApp());
DesiredCapabilities cap = new DesiredCapabilities();
cap.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
cap.setCapability(MobileCapabilityType.PLATFORM_VERSION, "11.0");
cap.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
cap.setCapability(MobileCapabilityType.AUTOMATION_NAME, "uiautomator2");
cap.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
URL url = new URL("http://localhost:4723/wd/hub");
driver = new AndroidDriver<>(url, cap);
basePage = PageFactory.initElements(driver, BasePage.class); //pagefactory initialised
}
public void login(String sheetname, int rowNumber) throws InterruptedException, IOException, InvalidFormatException {
FeatureUtils featureUtils = new FeatureUtils();
File excelDir = new File(classpathRoot, "");
File exceldoc = new File(excelDir, baseUtil.getUsersExcelDoc());
List<Map<String, String>> testData = featureUtils.getData(exceldoc.getAbsolutePath(), sheetname);
String username = testData.get(rowNumber).get("username");
String password = testData.get(rowNumber).get("password");
basePage.yesIAgreeButton.click(); //first element clicks successfully
This is the BasePage class holding the pagefactory
elements:
public class BasePage {
private final WebDriver driver;
public BasePage(WebDriver driver) { //constructor
this.driver = driver;
}
@FindBy(id = "com.test")
public WebElement yesIAgreeButton;
With the two classes above, the LoginTest class works as expected.
Now, I removed the DesiredCapabilities from the test class and put them in a new class, CapacityManager
:
public class CapacityManager {
public static AndroidDriver<AndroidElement> driver;
public static File classpathRoot;
private final BaseUtil baseUtil = new BaseUtil();
private static BasePage basePage;
public DesiredCapabilities appDesiredCapabilities() throws MalformedURLException {
DesiredCapabilities desiredCapabilities = null;
classpathRoot = new File(System.getProperty("user.dir"));
File appDir = new File(classpathRoot, "");
File app = new File(appDir, baseUtil.getMyApp());
DesiredCapabilities cap = new DesiredCapabilities();
cap.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
cap.setCapability(MobileCapabilityType.PLATFORM_VERSION, "11.0");
cap.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
cap.setCapability(MobileCapabilityType.AUTOMATION_NAME, "uiautomator2");
cap.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
URL url = new URL("http://localhost:4723/wd/hub");
driver = new AndroidDriver<>(url, cap);
basePage = PageFactory.initElements(driver, BasePage.class); //pagefactory initialisation
return desiredCapabilities;
}
}
I then called the DesiredCapabilities
from the test class, like this:
public class LoginTest {
private final BaseUtil baseUtil = new BaseUtil();
private static BasePage basePage;
public static AndroidDriver<AndroidElement> driver;
public static File classpathRoot;
CapacityManager capacityManager = new CapacityManager();
public void startApp() throws MalformedURLException {
capacityManager.appDesiredCapabilities(); //method call. App launches successfully.
}
public void login(String sheetname, int rowNumber) throws InterruptedException, IOException, InvalidFormatException {
FeatureUtils featureUtils = new FeatureUtils();
File excelDir = new File(classpathRoot, "");
File exceldoc = new File(excelDir, baseUtil.getUsersExcelDoc());
List<Map<String, String>> testData = featureUtils.getData(exceldoc.getAbsolutePath(), sheetname);
String username = testData.get(rowNumber).get("username");
String password = testData.get(rowNumber).get("password");
basePage.yesIAgreeButton.click(); //getting nullpointer error on this line. Looks like an issue with the pagefactory elements initialisation. basePage is null.
driver.pressKey(new KeyEvent(AndroidKey.TAB));
Objects represent real world entities. For example (taking a page out of the Head First Java reference), a cat is an object. A cat has legs and mouth as features which can be used for doing certain things like running and biting.
Likewise when you created the
CapacityManager
class and callednew
operator on it in theLoginTest
, you have created an object.CapacityManager
hasdriver
, andBasePage
(among other features) using which you have initialized in theappDesiredCapabilities()
method.In the case of the Cat, we cannot use the cat's legs to run and use the cat's mouth to bite (there is obviously a way to do this in java but we are getting ahead of ourselves at this point). We can tell the cat to run and bite but in the end the cat has to do these operations by itself. Likewise,
CapacityManager
features likedriver
andBasePage
cannot be used by us from outside theCapacityManager
. We can call theCapacityManager.appDesiredCapabilities()
method to initialize the driver, and set page factory onBasePage
but we cannot use them directly.Simply put, declaring
driver
andBasePage
in theLoginTest
and creating an object ofCapacityManager
does not initialize thedriver
andBasePage
features in theLoginTest
. We have to figure out how to control thedriver
andBasePage
declared in theCapacityManager
inLoginTest
. For this we usepublic
access modifier in theCapacityManager
fordriver
andBasePage
. The correct OOPs way is to usegetters
to make the features public so that we can get access to them from outside. This is shown in the below code update.There are a lot of different and better ways to configure this. If you are feeling even more fancy, you can create a class for getting the testdata. That is for another day.
Hopefully the solution above will solve the error you are getting!