0

这是我的测试类,我想在新浏览器中并行执行 Data Provider 的每个输入。我能够打开新的浏览器,但我得到 Session Not Found Exception 并且没有这样的元素异常

public class DemoTest {
private WebDriver driver;
@Test(dataProvider = "dp")
public void f(Integer n, String s) {
  try {
      System.out.println("Driver: "+driver.toString());
      driver.get("www.google.com");
      driver.findElement(By.id("lst-ib")).sendKeys("1234567");
      System.out.println("method f id:"+Thread.currentThread().getId()+" n:"+n+" s:"+s);
  }
  catch(Exception e) {
      e.printStackTrace();
  }
}
@BeforeMethod
public void beforeMethod() {
  try {
  driver= new FirefoxDriver();
  driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
  driver.manage().window().maximize();
  System.out.println("Before method id:"+Thread.currentThread().getId());
  }
  catch (Exception e) {
      e.printStackTrace();
  }
 }

@AfterMethod
public void afterMethod() {
  try {
      System.out.println("After method id:"+Thread.currentThread().getId());
  if(driver != null ) {
  driver.quit();
 // driver.close();
  }
  }
  catch(Exception e) {
      e.printStackTrace();
  }
}


@DataProvider(parallel=true)
public Object[][] dp() {
return new Object[][] {
  new Object[] { 1, "a" },
  new Object[] { 2, "b" },
  new Object[] { 3, "c" },
  new Object[] { 4, "d" },

};
}
}

这是 testng.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >

<suite name="Suite" parallel="methods"> 
<test name="prelogin">
<classes>
    <class name="com.package.DemoTest"></class>
</classes>
</test>
</suite> 

谁能告诉我为什么我得到这个异常以及如何解决它?

4

2 回答 2

3

您正在WebDriver跨多个线程共享一个实例。因此,一个测试可以WebDriver在另一个测试afterMethod已经退出它(因此会话未找到异常)或尚未加载 google.com(因此没有此类元素异常)之后尝试使用。

如果您想使用 TestNG 并行运行 Selenium WebDriver 测试,那么您可以使用 aThreadLocal来维护WebDriver每个线程的实例。

例如

public class DemoTest {
    private static final ThreadLocal<WebDriver> WEB_DRIVER_THREAD_LOCAL = new InheritableThreadLocal<>();

    @Test(dataProvider = "dp")
    public void f(Integer n, String s) {
        WebDriver driver = WEB_DRIVER_THREAD_LOCAL.get();
        System.out.println("Driver: " + driver.toString());
        driver.get("www.google.com");
        driver.findElement(By.id("lst-ib")).sendKeys("1234567");
        System.out.println("method f id:" + Thread.currentThread().getId() + " n:" + n + " s:" + s);
    }

    @BeforeMethod
    public void beforeMethod() {
        WebDriver driver = new FirefoxDriver();
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        driver.manage().window().maximize();
        WEB_DRIVER_THREAD_LOCAL.set(driver);
        System.out.println("Before method id:" + Thread.currentThread().getId());
    }

    @AfterMethod
    public void afterMethod() {
        WebDriver driver = WEB_DRIVER_THREAD_LOCAL.get();
        System.out.println("After method id:" + Thread.currentThread().getId());
        if (driver != null) {
            driver.quit();
        }
    }


    @DataProvider(parallel = true)
    public Object[][] dp() {
        return new Object[][]{
                new Object[]{1, "a"},
                new Object[]{2, "b"},
                new Object[]{3, "c"},
                new Object[]{4, "d"},

        };
    }
}

我省略了用 try-catch 块包装每个测试,因为 TestNG 已经捕获了测试/配置方法抛出的异常并为它们打印堆栈跟踪等。

上面的示例将为每个测试创建一个WebDriver与测试线程关联的实例。即,如果它们真正并行运行,您将打开 4 个 Firefox 实例(我认为这是您想要的)。

如果您有比线程更多的测试并且想要重用WebDriver实例,那么您可以使用具有初始值的 ThreadLocal。

例如

public class DemoTest {
    private static final Set<WebDriver> WEB_DRIVERS = new HashSet<>();
    private static final ThreadLocal<WebDriver> WEB_DRIVER_THREAD_LOCAL = InheritableThreadLocal
            .withInitial(new Supplier<WebDriver>() {
                @Override
                public WebDriver get() {
                    WebDriver driver = new FirefoxDriver();
                    driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
                    driver.manage().window().maximize();
                    WEB_DRIVERS.add(driver);
                    System.out.println("Before thread id:" + Thread.currentThread().getId());
                    return driver;
                }
            });

    @Test(dataProvider = "dp")
    public void f(Integer n, String s) {
        WebDriver driver = WEB_DRIVER_THREAD_LOCAL.get();
        System.out.println("Driver: " + driver.toString());
        driver.get("www.google.com");
        driver.findElement(By.id("lst-ib")).sendKeys("1234567");
        System.out.println("method f id:" + Thread.currentThread().getId() + " n:" + n + " s:" + s);
    }

    @AfterClass
    public void afterClass() {
        for (WebDriver webDriver : WEB_DRIVERS) {
            try {
                webDriver.quit();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    @DataProvider(parallel = true)
    public Object[][] dp() {
        return new Object[][]{
                new Object[]{1, "a"},
                new Object[]{2, "b"},
                new Object[]{3, "c"},
                new Object[]{4, "d"},

        };
    }
}

还有一个 testng.xml 来减少线程总数来证明这一点:

<suite name="Suite" parallel="methods" thread-count="2" data-provider-thread-count="2">
    <test name="prelogin">
        <classes>
            <class name="DemoTest"/>
        </classes>
    </test>
</suite>

示例输出(看看它如何只创建 2 个 FirefoxDriver 实例,并行运行两个测试,然后并行运行接下来的两个测试,使用所有可用线程并为每个线程重用 Web 驱动程序):

Before thread id:14
Driver: FirefoxDriver: firefox on WINDOWS (e924b5f1-9ace-46e5-a6b3-d1494de7e94d)
method f id:14 n:2 s:b
Before thread id:13
Driver: FirefoxDriver: firefox on WINDOWS (8dc8a53c-5a96-41e8-9383-e552c7c8f680)
method f id:13 n:1 s:a
Driver: FirefoxDriver: firefox on WINDOWS (8dc8a53c-5a96-41e8-9383-e552c7c8f680)
method f id:13 n:3 s:c
Driver: FirefoxDriver: firefox on WINDOWS (8dc8a53c-5a96-41e8-9383-e552c7c8f680)
method f id:13 n:4 s:d
于 2015-12-04T15:36:35.080 回答
0

问题与数据提供者无关。问题在于driver.get("www.google.com");。WebDriver api 向 Selenium 服务器发送 RESTfull 请求以执行命令。REST 服务使用httphttps协议进行请求/响应。因此,当我们在没有提及协议前缀(在本例中为 http)的情况下调用 url 时,会引发异常。

改成 :

driver.get("http://www.google.com/");

这将起作用。

于 2015-12-04T10:59:50.837 回答