【问题标题】:Cleaning up webdriver only in thread running without closing all drivers running in other threads仅在线程运行中清理 webdriver,而不关闭在其他线程中运行的所有驱动程序
【发布时间】:2019-08-01 16:33:17
【问题描述】:

我有每天早上运行的自动化回归测试。目前,它同时启动了几十个线程,每个线程在每个线程中运行自己的 webdriver。

                ChromeOptions option = new ChromeOptions();
                option.AddArgument("--headless");
                IWebDriver driver = new ChromeDriver(option);                    

                try
                {
                    SuiteDriver(driver, suiteTable);
                    LogMonitor.UEErrorHandling();
                }
                catch (Exception ex)
                {
                    WritetoLogFile("Exception in Main - " + ex);
                }
                finally
                {
                    workbook.Dispose();
                    driver.Quit();
                }

当测试完成时,还有一堆 webdriver 实例仍在运行。当我尝试在测试运行结束时使用 driver.Quit() 清理这些时,它关闭的不仅仅是驱动程序在自己的线程中,导致其他测试无法完成。 Driver.Quit() 似乎没有区分由这个实例启动的驱动程序和由测试的其他实例启动的其他驱动程序。

有没有办法确保 driver.Quit() 或 driver.Close() 仅关闭由仅在该线程中运行的特定可执行文件启动的 webdriver 实例?

【问题讨论】:

  • 您必须为每个线程使用 ThreadLocal 实例。退出驱动程序时,您将不得不使用线程特定的驱动程序。这方面的例子很多。
  • 解释:即使每个线程都有自己的 Chrome 实例,它们都共享驱动浏览器的同一个 chromedriver 可执行文件...当您调用 quit() 时,它会停止 chromedriver 进程和所有来自其他线程的后续请求无法再与浏览器通信。 ——

标签: c# multithreading selenium webdriver


【解决方案1】:

下面是在C# 中使用System.Threading.ThreadLocal 的线程安全执行示例

ThreadLocal<IWebDriver> DriversThread = new ThreadLocal<IWebDriver>();

IWebDriver Driver
{
    set => DriversThread.Value = value;
    get => DriversThread.Value;
}

string directoryPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); // Pass this directory path to chromedriver when you are installing chromedriver through Nuget packages.
ChromeOptions chromeOpt = new ChromeOptions();
chromeOpt.AddArguments("--headless");
Driver = new ChromeDriver(directoryPath, chromeOpt);

Driver.Url = "https://google.co.in";

Driver.Quit();

这将设置线程特定的驱动程序,无论执行多少线程,每个线程都有自己的驱动程序。

【讨论】:

  • 感谢您的帮助,阿普。上面您首先实例化 IWebDriver 的行是我发现使用 ThreadLocal 执行此操作的唯一方法。但是我找不到指定 ChromeDriver 的方法,并且上面的代码对我不起作用。
  • 我已经通过识别 pid 并关闭它们来做到这一点。我在这里尝试快速搜索并看到了这个帖子 - stackoverflow.com/questions/5901679/…。看看这是否有帮助。
  • @headlyvonnoggin 在指定 ChromeDriver 时遇到了什么问题?我已经编辑了答案以添加 chrome 选项和驱动程序可执行文件的路径(您必须通过 nuget 包安装 chromedriver)。让我知道这是否有帮助。
【解决方案2】:

尝试为每个网络驱动程序提供其自己的配置文件,如果需要,还提供下载路径。

private ChromeOptions GetChromeOptions()
{
    var options = new ChromeOptions();

    ProfilePath = Path.Combine(AppContext.BaseDirectory, "tmp", Guid.NewGuid().ToString());
    DownloadPath = Path.Combine(ProfilePath, "Downloads");
    if (!Directory.Exists(DownloadPath))
    {
        Directory.CreateDirectory(DownloadPath);
    }
    options.AddUserProfilePreference("download.default_directory", DownloadPath);
    //--lang=en-US,en headless does not define a language by default 
    options.AddArguments("--incognito", "--lang=en-US,en", $@"--user-data-dir={ProfilePath}");
    return options;
}

我正在使用 xUnit 生成数十个无头 chrome 测试,但我从未见过 dispose 关闭所有实例。我能想到的唯一区别是我每个人都有自己的个人资料。

我建议在基类上使用测试框架的设置和拆卸来处理所有测试的设置和拆卸。

public class PageLoad: IDisposable
{
    private IWebDriver _driver;

    public void PageLoad()
    {
        _driver = new ChromeDriver();
    }

    [Fact]
    public void PageLoadTest()
    {
        _driver.Navigate().GoToUrl("http://google.com");
        Assert.True(_driver.FindElement(By.XPath("//*[@id='hplogo']")).Displayed);
    }

    public void Dispose()
    {
        _driver.Dispose();
    }
}

您也可以将驱动程序包装在 using 语句中

using (var driver = new ChromeDriver())
{
    driver.Navigate().GoToUrl("http://google.com");
    Assert.True(_driver.FindElement(By.XPath("//*[@id='hplogo']")).Displayed);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-13
    • 1970-01-01
    相关资源
    最近更新 更多