在Java中,检查Selenium WebDriver是否已退出的最佳方法是什么?

34

我需要检查一组页面对象,以确定每个页面对象上的WebDriver是否已调用quit()方法。

我编写了以下方法来检查WebDriver的状态:

public static boolean hasQuit(WebDriver driver) {
        try {
            driver.getTitle();
            return false;
        } catch (SessionNotFoundException e) {
            return true;
        }
}

问题在于:我不喜欢为了发现一个布尔值的真相而不得不抛出和捕获异常,但是似乎我别无选择,因为 WebDriver API 没有提供检查驱动程序是否已退出的方法。

所以我的问题是,有没有更好的方法来检查WebDriver是否已退出?

我在这里找到了一个类似(且更一般化)的问题(链接),但该问题没有任何经过尝试的代码,并且唯一的答案是在退出后始终将WebDriver设置为null(我可能无法控制)。


你可以尝试查找firefox/chrome/IE进程是否正在运行。然后你可以决定浏览器是打开还是关闭。非常果断的决定。 - Vinay
在某些情况下,退出后将驱动程序设置为null可能有效,但在很多情况下,您仍然可能有对驱动程序对象的其他引用,因此驱动程序不会被垃圾回收。因此,大多数情况下,在退出后设置null并不能保证解决问题。 - James Dunn
3个回答

25

如果已经调用了quit(),那么driver.toString()会返回null:

>>> FirefoxDriver: firefox on XP (null))
否则,它将返回对象的哈希码:
>>> FirefoxDriver: firefox on XP (9f897f52-3a13-40d4-800b-7dec26a0c84d)

因此,在分配布尔值时,您可以检查是否为空:

boolean hasQuit = driver.toString().contains("(null)");

7
不应该依赖于toString()来进行编程行为。如果你深入研究了这个函数,你会注意到null来自于sessionId,所以你只需要检查getSessionId()是否返回null。然而,最终Sajan的回答更加可靠,因为并不保证所有实现都将sessionId设置为null,但是你可以保证stopClient()将被调用。 - Gili
1
@Gili 你说得对,需要检查 getSessionId() == null。然而,Sajan的答案并不更可靠,因为它只在WebDriver实例已被子类化为他建议的方式时才有效,并且不能保证WebDriver实际上已以这种方式进行了子类化。 - James Dunn
1
如果驱动程序可执行文件仍在运行,但由于某些原因浏览器已关闭,则此方法无效。在这种情况下,“driver.toString().contains("(null)")”部分将返回false,但是如果我尝试通过驱动程序访问浏览器,它将抛出异常。另外,“?true:false”部分是多余的。你应该只写 “boolean hasQuit = driver.toString().contains("(null)");”。 - dnk.nitro
1
@dnk.nitro:注意到了过多的布尔赋值。我进行了编辑。我相信Pat Meeker不会介意。 - James Dunn
对于那些挑剔于依赖字符串的人,这只是需要的想法而已。那个人并没有告诉你该怎么做,只是改变一下你的if逻辑,别再抱怨了。也许试着去帮助别人,而不是拥有奇怪的优越感。 - Husk Rekoms
显示剩余2条评论

16

基本上有两种方法,取决于你的情况。

情况1:扩展WebDriver不是一个现实的选项。

这是最常见的情况。 在实际工作中使用Selenium的大多数开发人员都希望有一种方便的方式来告诉他们是否已经退出了WebDriver,而且试图重构框架以确保仅使用自定义的WebDriver扩展可能并不值得麻烦。

在这种情况下,Sajan的回答和Gili关于他的回答的建议将不会有用,因为覆盖RemoteWebDriver#stopClient()不是一个选项。(此外,即使是选项,大多数人也在寻找简单的答案。)

只要您只使用随Selenium附带的标准WebDriver实现(FirefoxDriver、ChromeDriver、InternetExplorerDriver、SafariDriver等),您就可以将WebDriver强制转换为RemoteWebDriver,然后检查sessionId是否为null(Pat的做法是正确的,但直接调用sessionId比使用toString()更好)。

public static boolean hasQuit(WebDriver driver) {
    return ((RemoteWebDriver)driver).getSessionId() == null;
}

这个答案适用于95%的情况,因为你有多少次会使用一个没有实现RemoteWebDriver的WebDriver呢?(很少)

情况2:您可以实际扩展WebDriver。

这种情况较少见,但也许您是:
    (a)  与良好设计和抽象框架一起工作,或者
    (b)  从头开始构建selenium测试框架。

在这种情况下,您可以创建自己的接口来扩展WebDriver:

public interface CustomDriver extends WebDriver {

    boolean hasQuit();

}

然后你可以像这样扩展标准的WebDrivers(在这个例子中是ChromeDriver):

public class CustomChromeDriver extends ChromeDriver implements CustomDriver {

    boolean hasQuit = false;

    @Override
    public boolean hasQuit() {
        return hasQuit;
    }

    @Override
    public void stopClient() {
        super.stopClient();
        hasQuit = true;
    }
}

这是正确的方法,但它是否考虑了驱动程序崩溃的情况(例如 BROWSER_TIMEOUT)? - Jezor

5

StopClient 方法将在调用 quit (RemoteWebDriver 源码) 后被调用,你可以子类化你的 RemoteWebDriver 实例并重写 stopClient 方法,设置一些标志并检查该标志以确定 webdriver 是否已关闭 (quit)。


总的来说,我喜欢你的想法,但是: (1)我不一定控制正在使用的WebDriver实例的实现; (2)我可能希望避免在驱动程序上调用自己的方法,因为它没有在WebDriver接口中声明。 但除此之外,这是一个很好的想法,展示了对RemoteWebDriver内部工作的良好了解,所以+1。 - James Dunn
不幸的是,我们必须像之前展示的那样做,或者将WebDriver设置为null并进行检查。 - Sajan Chandran

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接