【问题标题】:Selenium2 - Running tests on CI causes multiple driver instancesSelenium - 在 CI 上运行测试会导致多个驱动程序实例
【发布时间】:2017-04-06 17:38:34
【问题描述】:

对于我们的 BDD 测试,我们使用与 selenium 2 webdriver(本例中的 Chrome 驱动程序)对话的 Specflow。

在本地主机上运行时(是的,“它在我的机器上工作”已经在谈话中出现了几次)测试工作正常。他们设置数据和新的 webdriver,进行测试,然后拆除 webdriver 和数据。即使由于我使用了正确的属性而导致测试出现严重错误,但总是会触发拆卸,因此 driver.Quit() 正在运行破坏浏览器和驱动程序。

当我使用我们的持续集成 [TeamCity] 在我们的服务器 [Windows Server 2008 r2] 上运行它时出现了问题。由于某种原因,它会开始运行多个驱动程序实例,从而导致测试失败。

以前有没有人遇到过这个问题并找到了解决方法?我们需要一个使用不是 HtmlUnitDriver的驱动程序的解决方案。

额外信息:

  • 语言 = C#
  • 服务器 = Windows Server 2008 R2
  • CI = 团队城市

编辑: 通过确保尚未创建 Webdriver 来设置 Webdriver,然后创建 ChromeDriver 的新实例。下面的伪/真实代码示例显示了它的设置方式,对不起,我无法显示完整的代码,因为它有很多绒毛,我们用于我们坚持使用的其他选项(例如 zap 或提琴手集成/语言更改等)。

设置

[SetUp]
[BeforeScenario()]
public static void BeforeWebScenario()
{
   if driver == null
     driver = new ChromeDriver();
   // Code to start page
}

拆掉

[TearDown]
[AfterScenario()]
public static void AfterWebScenario()
{
   try
   {
       driver.Quit();
   } catch (Exception)
   {
       throw Exception
   }
   driver = null;
}

【问题讨论】:

  • 你能给出一个重现这个的样本测试吗?
  • 两个问题:首先,您是如何启动驱动程序的,使用 ChromeDriver 还是 RemoteWebDriver?其次,您的测试驱动程序的典型构造函数是什么样的?
  • 您好,感谢您的关注,因为他们使用我创建的框架并操作页面对象模型(有很多抽象),所以很难给出示例测试。我将编辑帖子以显示驱动程序的设置方式。

标签: selenium continuous-integration selenium-webdriver specflow selenium-chromedriver


【解决方案1】:

我也有这个问题。我通过在我的 testSetup() 方法中杀死任何正在运行的 chromedriver.exe 实例来修复它。我使用了一个 VBScript 和一些 Groovy 代码来运行这些脚本。抱歉,这个答案有点长。

我的设置中有这个):

if (wshsc.isRunningByCommandLineContents("chromedriver.exe"))
    wshsc.killProcessByCommandLineContents("chromedriver.exe")

isRunningByCommandLineContents:

If WScript.Arguments.Count = 1 Then

strCmdLine = WScript.Arguments.Item(0)
On Error Resume Next
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set objShell = CreateObject("WScript.Shell")
Set colProcessList = objWMIService.ExecQuery _
    ("Select * from Win32_Process")
If colProcessList.Count > 0 Then
    For Each objItem in colProcessList
        If (InStr(objItem.CommandLine, strCmdLine)) Then
            If (InStr(objItem.CommandLine, "cscript")) Then
            Else
                WScript.StdOut.Write "A process is running with " + strCmdLine + " in its command line = " + objItem.Name
            End If  
        End If
    Next
End If
End If

killProcessByCommandLineContents:

If WScript.Arguments.Count = 1 Then
strProcess = WScript.Arguments.Item(0)
On Error Resume Next
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set objShell = CreateObject("WScript.Shell")
Set colProcessList = objWMIService.ExecQuery _
    ("Select * from Win32_Process")

If colProcessList.Count > 0 Then
    For Each objItem in colProcessList
        If InStr(objItem.CommandLine, strProcess) Then
            If (InStr(objItem.CommandLine, "cscript")) Then
            Else
                WScript.StdOut.Write objItem.Name + " "
                objItem.Terminate()
            End If
        End If
    Next
Else
    WScript.StdOut.Write "No instances found running"
End If
Else
WScript.StdOut.Write "Bad Arguments"
End If

还有“运行脚本部分”:

public void killProcessByCommandLineContents(String contents) {
    List<String> arg = new ArrayList<String>()
    arg.add(contents)
    String [] args = arg.toArray()
    runScript("killByCmdLineContents.vbs", args, true)
}
public boolean isRunningByCommandLineContents(String contents) {
    List<String> arg = new ArrayList<String>()
    arg.add(contents)
    String [] args = arg.toArray()
    String returnData = runScript("IsRunningByCmdLineContents.vbs", args, true)
    if (returnData.contains(contents)) {
        return true
    } else {
        return false 
    }
}
public String runScript(String name, String [] args, boolean returnOutput) {
    String s = null;
    List<String> cmdLine = new ArrayList<String>()
    cmdLine.add("C://Windows//System32//cscript.exe")
    cmdLine.add(dir + "dir//src//com//misc//wshScripts//" + name)
    int index = 0
    args.each() {
        cmdLine.add(args[index])
        index++
    }

    try {
        String [] cmdLineArray = cmdLine.toArray()
        Process p = Runtime.getRuntime().exec(cmdLineArray, null);
        if (returnOutput) {
            BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
            BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
            String dataToReturn
            Log.logger.info("Standard output: ");
            while ((s = stdInput.readLine()) != null) {
                Log.logger.info(s)
                dataToReturn = s // should get last line
            }

            Log.logger.info("Standard error: ");
            while ((s = stdError.readLine()) != null) {Log.logger.info(s);}
            return dataToReturn
        } else {
            return ""
        }
    }
    catch (IOException e) {
        Log.logger.info(e.message, e);
    }
}

【讨论】:

  • 谢谢,这似乎可以解决问题,至少在我找出为什么它开始创建它们之前。我将在今晚运行我们的通宵构建,明天将结果回复给您。谢谢
  • 感谢这帮助我确定了真正的问题(我也将其保留为一个很好的整理)。我在构建服务器上收到“OpenQA.Selenium.WebDriverException:服务器对 url 没有响应”。当我对此进行调查时,似乎在使用 .FindElement(obj) 之后的任何时候你都应该执行 Thread.Sleep(200),因为如果调用了太多的 find,就会出现某种竞争条件。
【解决方案2】:

如果您使用 DriverService 接口,请保持服务直到您完成驱动程序,然后调用 DriverService.stop()。对我来说,driver.quit() 还不够,因为我也在使用 DriverService。

driver.close();
driver.quit();
driverService.stop();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 2017-12-30
    • 2020-03-22
    相关资源
    最近更新 更多