当前位置: 首页 > 知识库问答 >
问题:

将硒与TestNg一起使用,测试指南适配器正在混合测试,驱动程序似乎在测试类之间共享

陆子石
2023-03-14

我正在使用硒(硒服务器独立2.47.1.jar)网格运行并行测试,该网格由Ant启动,由蚂蚁启动,并使用测试通知器适配器。屏幕截图是在侦听者的“测试失败”方法中拍摄的。问题在于,侦听器似乎对它应该使用哪个驱动程序感到困惑,有时会截取错误的浏览器窗口的屏幕截图,或者如果它认为应该使用的驱动程序已经退出,则完全失败。

当测试开始时,TestNg 的@BeforeTest和测试提示器的“onTestStart”方法在同一线程上运行,但是当测试失败时,测试提示程序的“onTestFailure”方法似乎在单独的线程上运行。似乎线程以某种方式交叉/共享,但我不知道为什么。

这里是一些框架代码,非常感谢您的帮助。

基础测试类:

public class baseClassTests{

    protected AutomationUtils au;
    protected DriverUtils du;

    @BeforeTest(alwaysRun = true)
    @Parameters({ "selenium.OS", "selenium.browser" })
    public void beforeTest(String OS, String browser) {

        //these call simple private methods to know where to set up the driver
        String port = getPort(OS, browser);
        String host = getHost(OS);

        //make a driver utility object here, this makes a driver
        du = new DriverUtils(browser, host, port);

        //pass this driver utility object to another class of utilities
        //this 'AutomationUtils' class gets a RemoteWebDriver ('driver') by calling driver=du.getDriver();
        //the 'AutomationUtils' class is then the one that does all of the 'driver.findBy...' etc
        au = new AutomationUtils(du);
    }


    @BeforeMethod(alwaysRun = true)
    public void beforeMethod(Method m, ITestResult tr) {
        du.deleteCookies();
        testNgTestName = m.getName();
        print("Method: "+testNgTestName + "   Thread: "+Thread.currentThread().hashCode());
        //set the attribute of the ITestResult object so we can use the same object in the listener
        tr.setAttribute("du", du);
        tr.setAttribute("au", au);
    }

}

侦听器类

public class AmSimpleTestListener extends TestListenerAdapter {

    private DriverUtils driveU;
    private AutomationUtils AutoU;
    private RemoteWebDriver driver;
    private RemoteWebDriver augmentedDriver;
    private String methodName;
    private String browser;
    private String browserVersion;
    String testClass;




    @Override
    public void onTestStart(ITestResult tr) {
        //pick up the correct driver utility object from the test class/method we are in
        driveU = (DriverUtils) tr.getAttribute("du");
        AutoU = (AutomationUtils) tr.getAttribute("au");
        driver = du.getDriver();
        augmentedDriver = (RemoteWebDriver) new Augmenter().augment(driver);
        methodName = tr.getName();
        testClass=tr.getTestClass();  //sort of, I actually parse it up a bit
        browser = driveU.getBrowser();
        browserVersion = driveU.getBrowserVersion();
        print("Method: "+methodName + "   Thread: "+Thread.currentThread().hashCode());
    }

    @Override
    public void onTestFailure(ITestResult tr) {
       print("Method: "+tr.getName() + "   Thread: "+Thread.currentThread().hashCode());
        try{
            writeScreenshotFile();
        }
        catch (Exception e){
            Out.error("Unable to take screen shot");
            e.printStackTrace();
        }
    }


    private String writeScreenshotFile() {
        if (driver != null && driver.getSessionId() != null) {
            File scrShot = ((TakesScreenshot) augmentedDriver).getScreenshotAs(OutputType.FILE);
            File localPathToScreenShot = new File("/path/to/base/directory/"+testClass+"/"+methodName+".png");
            try {
                FileUtils.copyFile(scrShot, localPathToScreenShot);
            } catch (Exception e) {
                Out.error("Couldn't write screenshot to file");
            }
            return localPathToScreenShot.getAbsolutePath();
        }
        return "Could not get path.";
    }

}

DriverUtils类生成/提供驱动程序

public class DriverUtils {

    private RemoteWebDriver driver;
    private int timeout;
    private String browserVersion;
    private String browser
    private DesiredCapabilities caps;

    public DriverUtils(String browser, String host, String port) {
        String hostUrl = "http://" + host + ":" + port + "/wd/hub";
        this.browser=browser;
        //do some stuff here to set capabilties
        driver = new RemoteWebDriver(new URL(hostUrl), caps);
        browserVersion = driver.getCapabilities().getVersion();
    }

    public RemoteWebDriver getDriver() {
        return driver;
    }

    public AmBrowser getBrowser() {
        return browser;
    }

    public String getBrowserVersion() {
        return browserVersion;
    }


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

    public void deleteCookies(){
        driver.manage().deleteAllCookies();
    }


}


public class AutomationUtils extends BaseClassUtils {

    public AutomationUtils(DriverUtils driverUtils) {
        //pass it up to the base class utils (this is different than base class tests, above)
        //do this so the driver can be accessed by other utility classes as well
        super(driverUtils);
    }

    //All sorts of methods here to find elements, login, blah blah everything that is done with a driver object
}


public class BaseClassUtils { //this is a different class than BaseClassTests

    //make the driver a protected object so all utility classes can access as nec.
    protected final RemoteWebDriver driver;

    public BaseClassUtils(DriverUtils driverUtils) {
         driver = driverUtils.getDriver();
    }

}

测试是通过ant运行的。

<suite name="Dev2 for debugging" parallel="tests" thread-count="10">-- tests here </suite>

共有2个答案

微生令
2023-03-14

尝试使用ThreadLocal for RemoteWebDriver,以便它可以处理并行运行:

public class DriverUtils {
    private static ThreadLocal<RemoteWebDriver> driver = new ThreadLocal<~>();
    private int timeout;
    private String browserVersion;
    private String browser
    private DesiredCapabilities caps;

    public DriverUtils(String browser, String host, String port) {
        String hostUrl = "http://" + host + ":" + port + "/wd/hub";
        this.browser=browser;
        //do some stuff here to set capabilties
        driver.set(new RemoteWebDriver(new URL(hostUrl), caps));
        browserVersion = getDriver().getCapabilities().getVersion();
    }

    public RemoteWebDriver getDriver() {
        return driver.get();
    }

    public AmBrowser getBrowser() {
        return browser;
    }

    public String getBrowserVersion() {
        return browserVersion;
    }


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

    public void deleteCookies(){
        getDriver().manage().deleteAllCookies();
    }
}
朱鸿畅
2023-03-14

在修补了一段时间后,我得出结论,有两件事似乎很有帮助。

  1. 消除侦听器,并在@AfterMethod
  2. 中截取所有屏幕截图
  3. @前/后方法/测试方法移动到子类中,但只需调用父类中的方法来完成所有工作。

我注意到的另一件事是,对于#2,TestNG应该运行父< code>@Before方法,然后运行子< code>@Before方法;最后运行子“@After”方法,然后运行父< code>@After方法。< br >我运行了一系列简单的测试,发现所有的before/after方法都没有运行,所以对于在父级和子级中都使用< code>@Before和< code>@After方法的少数情况,我进行了合并。

现在事情似乎运行得更好了,驱动程序不会感到困惑,屏幕截图被附加到正确的浏览器/测试中。

 类似资料:
  • 我使用数据提供者方法和测试方法(测试方法中带有ITestContext参数)。一个简化的例子如下: 我的Retry类和RetryListener类如下: } 预期:当测试失败时,TestNG调用重试,然后数据提供程序应将相同的值返回给测试方法。 观察到:数据提供者返回相同的值,但测试方法没有运行,重试终止,下一个测试开始(数据提供者现在将返回新值) 但我的重试没有输入测试方法(测试方法不需要(in

  • 我有一个测试类的testng套件,我正在通过一个testng.xml文件运行它。这个很管用。所有测试都是串行运行的,因此没有并行执行障碍。 当然,通过类成员变量在单个类中的测试方法之间共享状态是很容易的,但是我不知道如何在测试类之间共享状态。

  • Rails 程序测试指南 本文介绍 Rails 内建对测试的支持。 读完本文,你将学到: Rails 测试术语; 如何为程序编写单元测试,功能测试和集成测试; 常用的测试方法和插件; 1 为什么要为 Rails 程序编写测试? 在 Rails 中编写测试非常简单,生成模型和控制器时,已经生成了测试代码骨架。 即便是大范围重构后,只需运行测试就能确保实现了所需功能。 Rails 中的测试还可以模拟浏

  • 我有一个Selenium项目,在本地机器上运行良好,但在Hudson运行时出现问题。问题是它不会在每次测试结束时关闭打开的驱动程序。 先决条件:此项目由Hudson在Selenium网格服务器上运行。(我也在Selenium网格服务器上的本地机器上运行了它,问题没有发生) 所以,我有一个由每个测试类实现的BeforeAndAfter类。 在BeforeAndAfter中,我有一个@BeforeCl

  • Vue CLI 提供了预配置的单元测试和 e2e 测试安装。 如果你有兴趣为 *.vue 文件手动设置单元测试,请查询 @vue/test-utils 的文档,这份文档涵盖了对 mocha-webpack 或 Jest 的设置。

  • 类似问题:在Android Studio中的Android工具测试和单元测试之间共享代码 我的设置如下: 包含单元测试的< li> 文件夹。这些可以是Java或Kotlin类 包含仪器测试的< li> 。这些也可以是Java或Kotlin类 < li> 是一个文件夹,其中包含一组在单元测试和测量测试之间共享的实用程序。 这种共享在gradle中定义为: 这允许< code>src/test或< c