Selenium结合TestNG时@BeforeClass与@AfterClass未执行问题
问题根因拆解
你遇到的@BeforeClass、@AfterClass方法完全不触发的问题,是TestNG调度逻辑和代码结构错配导致的,核心错配点如下:
- TestNG的注解调度规则存在认知偏差:TestNG只会扫描包含
@Test测试方法的类,触发对应类链路下的生命周期注解。如果一个类本身没有任何带@Test的方法,哪怕你把它单独列进TestNG XML的类列表,TestNG也会直接跳过该类的所有注解方法,根本不会执行其中的前置、后置逻辑。 - 类间关联完全断链:你目前的测试类
OpenTest和基类InitSetUp是完全独立的两个类,没有任何继承关系,TestNG在调度OpenTest的测试方法时,完全感知不到InitSetUp的存在,自然不会触发它内部的注解方法。 - 实例化方式完全不符合TestNG调度逻辑:你在
OpenTest的构造方法中手动new InitSetUp()对象,这个手动创建的实例和TestNG框架本身管理的对象完全隔离,就算InitSetUp里有注解方法,TestNG也不会对这个手动创建的对象做方法调度。 - 驱动传值逻辑失效:因为
@BeforeClass根本没有执行,你在OpenTest构造方法里调用baseclass.getDriver()拿到的永远是null值,就算前置逻辑能触发,两个独立的InitSetUp实例也会导致driver属性完全不共享。
修正方案
1. 调整类继承关系
删掉OpenTest里手动创建InitSetUp对象的逻辑,改成OpenTest直接继承InitSetUp。这样TestNG在调度OpenTest的测试方法时,会自动把父类的@BeforeClass、@AfterClass方法纳入生命周期调度链路,不需要手动创建实例。
2. 修正TestNG XML配置
把原来单独列在<classes>节点下的baseClasses.InitSetUp条目删掉,只保留实际带@Test方法的测试类即可。
3. 修复原有代码中的隐藏bug
- 给
setDriver方法里的switch分支补break关键字,避免分支穿透导致驱动重复初始化 - 修正Firefox初始化逻辑的笔误:原代码
initFirfoxDriver方法中错误创建了ChromeDriver实例,同时驱动配置键值写错(Firefox的系统属性键为webdriver.gecko.driver,不是webdriver.firefox.driver) - 修正传入的URL格式:原参数传的
google.com缺少协议头,WebDriver无法识别,需要补全为带https://的完整地址 - 给
tearDown方法增加空判断,避免driver为null时调用quit()抛空指针异常
4. 最终可运行的代码参考
修正后的InitSetUp基类:
package baseClasses; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.firefox.FirefoxDriver; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Parameters; public class InitSetUp { // 改成protected修饰,子类可直接访问继承的driver对象 protected WebDriver driver; private static String baseDriverPath="D:\\driver\\"; public WebDriver getDriver() { return driver; } private void setDriver(String browserName, String url) { switch(browserName) { case "Chrome" : System.out.println("Setting chrome driver please wait"); driver = initChromeDriver(url); break; case "Firefox" : System.out.println("Setting firefox driver please wait"); driver = initFirefoxDriver(url); break; case "IE" : // 补充IE驱动初始化逻辑即可 break; } } private WebDriver initChromeDriver(String url) { System.out.println("initializing chrome driver please wait"); System.setProperty("webdriver.chrome.driver", baseDriverPath + "chromedriver.exe"); WebDriver driver = new ChromeDriver(); System.out.println("Navigating to given url please wait"); driver.navigate().to(url); return driver; } private WebDriver initFirefoxDriver(String url) { System.out.println("initializing Firefox driver please wait"); System.setProperty("webdriver.gecko.driver", baseDriverPath + "geckodriver.exe"); WebDriver driver = new FirefoxDriver(); System.out.println("Navigating to given url please wait"); driver.navigate().to(url); return driver; } @Parameters({"browserName","openURL"}) @BeforeClass public void initBrowser(String browserName,String openURL) { System.out.println("Initializing Class.."); try { setDriver(browserName, openURL); } catch (Exception e) { e.printStackTrace(); } } @AfterClass public void tearDown() { System.out.println("Quiting please wait"); if(driver != null) { driver.quit(); } } }
修正后的OpenTest测试类:
package testClasses; import org.testng.annotations.Test; import baseClasses.InitSetUp; // 直接继承基类,替代原来手动new对象的逻辑 public class OpenTest extends InitSetUp { @Test public void openBroser() { System.out.println("TEST ONE"); // 可直接使用父类继承来的driver做页面操作 System.out.println("当前页面标题:" + driver.getTitle()); } }
修正后的TestNG XML配置:
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd" > <suite name="TESTX" verbose="1" > <parameter name="browserName" value="Firefox" /> <parameter name="openURL" value="https://www.google.com" /> <test name="TestOpen" > <classes> <!-- 只保留带实际测试方法的类,删除原来多余的InitSetUp条目 --> <class name="testClasses.OpenTest" /> </classes> </test> </suite>
内容的提问来源于stack exchange,提问作者MTK
相关产品推荐
相关产品推荐

