我正在使用 Java 和 TestNG 框架为我的公司编写一些 selenium 自动化 UI 测试。我在
Base
类中定义驱动程序,并且我想在 @BeforeTest
中实际初始化驱动程序并在 @AfterTest
方法中退出它。假设它们位于不同的类中,Java 的方法是什么?我知道如何让它在同一个班级中工作,但不能在不同的班级中工作。这是我的 Base.java
文件:
public class Base {
public static WebDriver driver = null;
public WebDriver getDriver() {
driver = new ChromeDriver();
return driver;
}
}
现在,我想要一个单独的安装类和一个单独的拆卸类。如果我要在同一个
@Test
中定义所有这些,我会这样做:
@Test
public void testOne() {
Base b = new Base();
WebDriver driver = b.getDriver();
// Do test-y things here.
driver.quit();
}
我该如何设置?尝试学习正确的方法来做到这一点,而不是一起破解某些东西。如果需要的话我还可以提供更多信息。谢谢!
使用继承。
public class TestBase {
protected WebDriver driver;
@BeforeClass
public void setUp(){
System.out.println("I am in setUp method.");
//WebDriver instantiation etc.
System.setProperty("webdriver.chrome.driver", "/path/to/chromedriver");
ChromeOptions options = new ChromeOptions();
options.addArguments("--start-maximized", "--disable-cache");
driver = new ChromeDriver(options);
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
}
@AfterClass
public void tearDown(){
System.out.println("I am in tearDown method.");
//You can clean up after tests.
driver.close();
}
}
然后就可以使用继承了。注意
extends
关键字:
public class ParticularTest extends TestBase {
@Test
public void testMethod() {
System.out.println("I am in testMethod.");
//Your driver from TestBase is accessible here.
//Your assertions come here.
}
}
稍后您可以执行
ParticularTest.java
。
输出:
I am in setUp method.
I am in testMethod.
I am in tearDown method.
我建议您不要在测试中使用这种实例化网络驱动程序的机制。根据定义,
@BeforeTest
预计每个<test>
标签都会被调用ONLY ONCE。因此,如果您的 TestNG 套件 xml 文件有类似这样的内容
<test name="MyTests">
<classes>
<class name="com.foo.Test1"/>
<class name="com.foo.Test2"/>
</classes>
</test>
并且如果
com.foo.Test1
和 com.foo.Test2
都扩展了 TestBase
类,那么 @Test
类中的 com.foo.Test2
方法在访问 NullPointerException
对象时必然会命中 driver
,因为你的 @BeforeTest
setup()
中带注释的 TestBase
方法将仅执行一次(对于 Test1
),并且对于 Test
不会执行,因为这两个类都从同一个基类扩展。
我建议您使用this(这是我的博客)之类的东西来进行网络驱动程序实例化。
I have a similar issue and need help to understand if my code needs any restructuring.
parent class
------------
package selenium.setup;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.WebDriver;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.Parameters;
public class SeleniumBaseTest {
protected final static ThreadLocal<WebDriver> webDriver = new ThreadLocal<>
();
@BeforeClass
@Parameters({"browser","baseURL"})
public void Setup(String browser, String baseURL) throws Exception{
webDriver.set(BrowserManager.doBrowserSetup(browser));
System.out.println("Before Test Thread ID:
"+Thread.currentThread().getId());
//get URL
webDriver.get().get(baseURL);
webDriver.get().manage().window().maximize();
webDriver.get().manage().deleteAllCookies();
webDriver.get().manage().timeouts().implicitlyWait(30,
TimeUnit.SECONDS);
}
@AfterClass
public void tearDown(){
webDriver.get().quit();
System.out.println("After Test Thread ID:
"+Thread.currentThread().getId());
webDriver.remove();
}
}`
Child class
-----------
`package selenium.trials;
import java.time.Duration;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.testng.ITestContext;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import selenium.setup.SeleniumBaseTest;
import selenium.utils.WebElementUtility;
public class SeleniumDragnDrop extends SeleniumBaseTest{
Logger logger;
WebDriver driver;
@BeforeTest(alwaysRun=true)
public void beforeTest(ITestContext testContext){
logger = LogManager.getLogger(this.getClass());
driver = webDriver.get();
logger.info("In dragNDrop beforeTest: Thread ID:
"+Thread.currentThread().getId());
}
@Test
public void dragNDrop() throws InterruptedException {
logger.info("In dragNDrop Thread ID: "+Thread.currentThread().getId());
WebElementUtility.clickOn(driver,driver.findElement(By.linkText("Drag and
Drop")), Duration.ofSeconds(15));
WebElement source = driver.findElement(By.id("column-a"));
WebElement dest = driver.findElement(By.id("column-b"));
Actions action = new Actions(driver);
action.dragAndDrop(source, dest).build().perform();
logger.info("After dragNDrop Thread ID: "+Thread.currentThread().getId());
}
@AfterTest
public void tearDown() {
logger.info("In dragNDrop tearDown : Thread ID:
"+Thread.currentThread().getId());
}
}`
package selenium.trials;
import java.awt.AWTException;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.ITestContext;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import selenium.setup.SeleniumBaseTest;
import selenium.utils.WebElementUtility;
public class SeleniumAlerts extends SeleniumBaseTest{
Logger logger;
WebDriver webDriver;
@BeforeMethod
public void beforeTest(ITestContext testContext){
logger = LogManager.getLogger(this.getClass());
//webDriver = driver.get();
logger.info("In testAlerts beforeMethod: Thread ID: "+Thread.currentThread().getId());
logger.info(" Driver " + driver.get().getCurrentUrl());
}
@Test
public void testAlerts() throws InterruptedException {
logger = LogManager.getLogger(this.getClass());
logger.info("In testAlerts Thread ID: "+Thread.currentThread().getId());
Thread.sleep(2000);
//driver = webDriver.get();
try {
WebElementUtility.clickOn(driver.get(),driver.get().findElement(By.linkText("JavaScript Alerts")), Duration.ofSeconds(15));
}catch(org.openqa.selenium.StaleElementReferenceException ex)
{
System.out.println(" current URL " + driver.get().getCurrentUrl());
WebElementUtility.clickOn(driver.get(),driver.get().findElement(By.linkText("JavaScript Alerts")), Duration.ofSeconds(15));
}
WebElement ele = driver.get().findElement(By.xpath("//button[text()='Click for JS Alert']"));
WebElementUtility.clickOnAlert(driver.get(),ele, Duration.ofSeconds(20),true);
WebElementUtility.clickOnAlert(driver.get(),driver.get().findElement(By.xpath("//button[text()='Click for JS Confirm']")), Duration.ofSeconds(20),false);
clickOnPrompt(driver.get(),driver.get().findElement(By.xpath("//button[text()='Click for JS Prompt']")), Duration.ofSeconds(20),false);
logger.info("In testAlerts Thread ID: "+Thread.currentThread().getId());
//driver.get().quit();
}
@AfterMethod
public void setDown() {
logger.info("In testAlerts setDown : Thread ID: "+Thread.currentThread().getId());
//driver.get().quit();
}
testng.xml
---------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="TestSuite" thread-count="2" parallel="classes">
<parameter name="browser" value="Chrome"/>
<parameter name="baseURL" value="https://the-internet.herokuapp.com"/>
<test name="SeleniumTrials" preserve-order="true">
<classes>
<class name="selenium.trials.SeleniumDragnDrop"/>
<class name="selenium.trials.SeleniumAlerts"/>
</classes>
</test>
</suite>
Log - The issue is for the second test, the browser does not close. that means the @AfterClass is not called. Its also evident from the fact that the logger.info for this test also is not logged.
---
17:23:10.015 [TestNG-test=SeleniumTrials-2] INFO selenium.trials.SeleniumAlerts - Before Class: Setup Thread ID: 23
17:23:36.591 [TestNG-test=SeleniumTrials-2] INFO selenium.trials.SeleniumAlerts - Before Class: Setup Thread ID: 24
17:23:40.558 [TestNG-test=SeleniumTrials-1] INFO selenium.trials.SeleniumDragnDrop - Before Class: Setup Thread ID: 23
17:24:15.498 [TestNG-test=SeleniumTrials-2] INFO selenium.trials.SeleniumAlerts - In testAlerts beforeMethod: Thread ID: 24
17:24:15.518 [TestNG-test=SeleniumTrials-2] INFO selenium.trials.SeleniumAlerts - Driver https://the-internet.herokuapp.com/
17:24:19.681 [TestNG-test=SeleniumTrials-2] INFO selenium.trials.SeleniumAlerts - In testAlerts Thread ID: 24
17:24:23.108 [TestNG-test=SeleniumTrials-1] INFO selenium.trials.SeleniumDragnDrop - In dragNDrop beforeMethod: Thread ID: 23
17:24:23.112 [TestNG-test=SeleniumTrials-1] INFO selenium.trials.SeleniumDragnDrop - In dragNDrop Thread ID: 23
17:24:28.017 [TestNG-test=SeleniumTrials-1] INFO selenium.trials.SeleniumDragnDrop - After dragNDrop Thread ID: 23
17:24:28.019 [TestNG-test=SeleniumTrials-1] INFO selenium.trials.SeleniumDragnDrop - In dragNDrop setDown : Thread ID: 23
17:24:40.756 [TestNG-test=SeleniumTrials-2] INFO selenium.trials.SeleniumAlerts - In testAlerts Thread ID: 24
17:24:40.760 [TestNG-test=SeleniumTrials-2] INFO selenium.trials.SeleniumAlerts - In testAlerts setDown : Thread ID: 24
17:24:55.176 [TestNG-test=SeleniumTrials-2] INFO selenium.trials.SeleniumAlerts - After Class: Setup Thread ID: 24