【问题标题】:Instantiating the same class from different classes从不同的类实例化同一个类
【发布时间】:2021-07-18 04:30:30
【问题描述】:

在 BaseTest.java 中,我有一个方法来初始化 AppiumDriver 类型的对象。 在 LogInTest.java 中,我正在创建 BaseTest 类的实例并调用 initializeDriver 方法。 再次在 LoginPage.java 我创建 BaseTest 类的另一个实例,但我没有调用 初始化驱动程序方法。由于在 LoginPage.java 中我只是创建了 BaseTest 类的实例,而不是调用 initializeDriver 方法,那么与 LoginPage.java 的 BaseTest 实例相关联的驱动程序对象不应该为 null 吗?

程序按照我老师的解释运行,但我只是不明白它在 LoginPage.java 中是如何运行的 base.getDriver() 应该为 null,因为我从未在那里调用 initializeDriver 方法。

BaseTest.java

package com.qa;

import java.io.File;
import java.io.FileInputStream;
import java.net.URL;
import java.util.Properties;

import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Parameters;

import com.utils.TestUtils;

import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileElement;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.pagefactory.AppiumFieldDecorator;
import io.appium.java_client.remote.MobileCapabilityType;

public class BaseTest {
    
    
    public BaseTest() {
        
        
    }
    
    protected static AppiumDriver driver;
    protected static Properties prop;
    protected FileInputStream fis;
    protected String dir;
    
    
    public void setDriver(AppiumDriver driver) {
        
        this.driver=driver;
    }
    
    public AppiumDriver getDriver() {
        
        return driver;
    }
    

    public void initializeDriver(String platformName,String platformVersion, String deviceName) {
        
    
        try {
            
            dir=System.getProperty("user.dir");
            fis=new FileInputStream(new File(dir+File.separator+"src"+File.separator+"main"+File.separator+"java"+File.separator+"com"+File.separator+"qa"+File.separator+"config.properties"));
            
            prop=new Properties();
            prop.load(fis);
            
            DesiredCapabilities cap=new DesiredCapabilities(); 
            
            
            cap.setCapability(MobileCapabilityType.PLATFORM_NAME, platformName);
            cap.setCapability(MobileCapabilityType.PLATFORM_VERSION, platformVersion);
            cap.setCapability(MobileCapabilityType.DEVICE_NAME, deviceName);
            cap.setCapability(MobileCapabilityType.AUTOMATION_NAME, prop.getProperty("UIAutomator2"));
            //cap.setCapability(MobileCapabilityType.UDID, "50");
            
            String appURL=dir+File.separator+prop.getProperty("appLocation"); 
            cap.setCapability(MobileCapabilityType.APP, appURL); // if you want to install and launch a new app
            cap.setCapability("autoGrantPermissions", true);
            //cap.setCapability(MobileCapabilityType.BROWSER_NAME, "Chrome");
            //cap.setCapability("chromedriverExecutable", "C:\\chromedriver-mobile_browser\\chromedriver.exe");
            //cap.setCapability("newCommandTimeout", 900); //how long 
            cap.setCapability("appPackage", prop.getProperty("androidAppPackage"));
            cap.setCapability("appActivity", prop.getProperty("androidAppActivity"));
            cap.setCapability("autoAcceptAlerts", "true"); // to accept all alerts
            //cap.setCapability("avdLaunchTimeout", "300000");
            cap.setCapability("unlockType", "pin");
            cap.setCapability("unlockKey", "74159");
            
            URL url=new URL(prop.getProperty("appiumURL"));
            
             driver=new AndroidDriver(url,cap);
             String sessionID=driver.getSessionId().toString();
            
        }
        catch(Exception e) {
            
            e.printStackTrace();
            
        }
        
        
        
        
        
        
    }
    
    
    public void waitForVisibility(MobileElement e) {
        
        WebDriverWait wait=new WebDriverWait(driver,TestUtils.WAIT);
        wait.until(ExpectedConditions.visibilityOf(e));
        
    }
    
    public void click(MobileElement e) {
        
        waitForVisibility(e);
        e.click();
    }
    
    public void sendKeys(MobileElement e, String keys) {
        
        waitForVisibility(e);
        e.sendKeys(keys);
        
    }
    
    public String getAttribute(MobileElement e, String attribute) {
        
        waitForVisibility(e);
        return e.getAttribute(attribute);
        
    }

    
    

    public void quitDriver() {
        
        
        driver.quit();
    }
    
    
    
    

    
}

LogInTest.java

package com.qa.test;
import org.testng.annotations.Test;
import com.qa.BaseTest;
import com.qa.pages.LoginPage;
import com.qa.pages.ProductsPage;
import io.appium.java_client.AppiumDriver;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Parameters;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import java.lang.reflect.Method;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
public class LogInTest{
    LoginPage logInPage;
    ProductsPage productsPage;
    BaseTest base;
    AppiumDriver driver;
    
    @Parameters({"platformName","platformVersion","deviceName"})
    @BeforeClass
    public void beforeClass(String platformName,String platformVersion,String deviceName) {
        
        base=new BaseTest();
        base.initializeDriver(platformName, platformVersion, deviceName);
        
    }
    
    @AfterClass
    public void afterClass() {
        
        base.quitDriver();
    }
    
    
  @BeforeMethod
  public void beforeMethod(Method m) {
      
      logInPage=new LoginPage();
      productsPage=new ProductsPage();
      System.out.println("Current test being executed "+m.getName());
  }
 
  
  @Test
  public void invalidUserName() {
      logInPage.enterUsername("Incorrect user");
      logInPage.enterPassword("secret_sauce");
      logInPage.clickLoginBtn();
      
      String expectedMsg="Username and password do not match any user in this service.";
      String errMsg=logInPage.getErrTxt();
      System.out.println("Error message is "+ errMsg);
      Assert.assertEquals(expectedMsg, errMsg);
  }
  
  @Test
  public void invalidPassword() {
      logInPage.enterUsername("standard_user");
      logInPage.enterPassword("Incorrect Password");
      logInPage.clickLoginBtn();
      
      String expectedMsg="Username and password do not match any user in this service.";
      String errMsg=logInPage.getErrTxt();
      System.out.println("Error message is "+ errMsg);
      Assert.assertEquals(expectedMsg, errMsg);
  }
  
  @Test
  public void validCredentials() {
      logInPage.enterUsername("problem_user");
      logInPage.enterPassword("secret_sauce");
      logInPage.clickLoginBtn();
      
      String title="PRODUCTS";
      String actTitle=productsPage.getTitle();
      System.out.println("Actual title is "+ actTitle);
      Assert.assertEquals(actTitle, title);
  }
}

LoginPage.java

package com.qa.pages;

import org.openqa.selenium.support.PageFactory;

import com.qa.BaseTest;

import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileElement;
import io.appium.java_client.pagefactory.AndroidFindBy;
import io.appium.java_client.pagefactory.AppiumFieldDecorator;

public class LoginPage {
    BaseTest base;
    
    public LoginPage() {
        base=new BaseTest();
        PageFactory.initElements(new AppiumFieldDecorator(base.getDriver()), this);
    }
    
    @AndroidFindBy(accessibility="test-Username")
    private MobileElement userNameTxtFld;
    
    @AndroidFindBy(accessibility="test-Password")
    private MobileElement passWordTxtFld;
    
    @AndroidFindBy(accessibility="test-LOGIN")
    private MobileElement logInBtn;
    
    
    @AndroidFindBy(xpath="//android.view.ViewGroup[@content-desc=\"test-Error message\"]/android.widget.TextView")
    private MobileElement errMsg;
    
    
    public LoginPage enterUsername(String userName) {
        
        base.sendKeys(userNameTxtFld,userName);
        
        
        return this;
    }
    
public LoginPage enterPassword(String passWord) {
        
        base.sendKeys(passWordTxtFld,passWord);
        
        
        return this;
    }

public String getErrTxt() {
    
    return base.getAttribute(errMsg,"text");
    
}


public ProductsPage clickLoginBtn() {
    
    base.click(logInBtn);
    
    
    return new ProductsPage();


}
}

【问题讨论】:

  • 如果你想让我在一个低得多的层次上扩展 static 的工作原理,请告诉我。我可以更新我的帖子以更详细地解释。

标签: java selenium appium


【解决方案1】:

解释是@BeforeClass注解。

【讨论】:

    【解决方案2】:

    您需要了解几件事。首先与关键字static 有关。我将仅涉及与此问题相关的信息。

    然后一个类的字段标记为static,这意味着该类的每个实例共享确切的变量。让我们看看你的BaseTest 类:

    public class BaseTest {
        public BaseTest() {} 
        
        protected static AppiumDriver driver; // shared variable
        ...
        protected String dir; // not shared
        
        public void setDriver(AppiumDriver driver) {
            this.driver=driver;
        }
    
    ... // more stuff in the class
    }
    

    如果 A 类和 B 类都创建了一个 BaseTest 的实例,并且一个设置了 AppiumDriver,那么如果第二个类也创建了自己的 BaseTest 实例,则它不必设置驱动程序。同样,如果 B 类更改了 AppiumDriver 的实例,它也会更改由 A 类创建的 BaseTest 对象持有的 AppiumDriver 对象。这就是将字段(变量)标记为静态的效果。

    第二件事与执行顺序有关。请记住,如果 A 类和 B 类都创建了一个 BaseTest 的实例,一旦其中一个设置了 AppiumDriver,它就会为两者设置它。但是,如果没有设置驱动程序的类尝试首先使用它怎么办?在这种情况下,毫无疑问,您将获得NullPointerException。也就是说,正如@rzwitserloot 在他或她的帖子中提到的,执行顺序由注释@BeforeClass 控制。所以你的教授是对的,因为,

    1. 实例化BaseTest 的类有一个在执行任何测试之前被调用的方法,该方法设置AppiumDriver 对象,并且
    2. AppiumDriver 对象是静态的,这意味着BaseTest 的每个实例共享同一个驱动程序对象。

    【讨论】:

    • 完美!谢谢你的详细解释
    猜你喜欢
    • 2019-03-12
    • 2019-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多