我正在浏览selenium中的屏幕截图代码。下面是它的代码:
File src = ((TakesScreenshot)driver).getScreenshotAs(OutputType.File);
在上面的行中,TakesScreenshot是一个接口,getScreenshotAs是一个方法。因此,我从中了解到,我们正在将驱动程序类型转换为TakesScreenshot接口,这本质上意味着我们的驱动程序从现在起将表现得像TakesScrenshot,之后将执行getScreenshotAs方法。
我的问题是接口只能有抽象方法。那么,getScreenshotAs方法是如何通过TakesScreenshot接口执行的,因为它没有这个方法的任何定义。更确切地说,getScreenshotAs方法是在哪里定义的,上面的代码行是如何工作的?
添加更多细节:
TakeScreenshot-->一个接口
driver-->ChromeDriver类的实例(WebDriver driver=new ChromeDrive())
TakesScreenshot接口中的getScreenshotAs-->方法。
上面的代码用于对selenium中的网页进行截图。
方法getScreenshotAs
在RemoteWebDriver类中实现。您不能从driver
实例中使用它,因为您使用了WebDriver
接口来创建driver
实例,该接口没有扩展TakesScreenshot
接口。
转换为(或首先使用)RemoteWebDriver
或ChromeDriver
也可以使用该方法。
File src = ((RemoteWebDriver)driver).getScreenshotAs(OutputType.File);
首先,让我对您的代码进行分解以进行解释:
File src = ((TakesScreenshot)driver).getScreenshotAs(OutputType.File);
进入这两行:
TakesScreenshot ts = (TakesScreenshot) driver;
File source = ts.getScreenshotAs(OutputType.FILE);
分析
根据文档,TakesScreenshot是org.openqa.selenium
包中Selenium中的一个接口。public interface TakesScreenshot
表示可以捕获屏幕截图并以下面提到的不同方式存储它的驱动程序。public interface TakesScreenshot
有一个名为WebElement的子接口。已知的实现类有:
- ChromeDriver
- FirefoxDriver
- InternetExplorerDriver
- 边缘驱动程序
- 操作驱动程序
- 远程Web驱动程序
- 远程WebElement `
- SafariDriver
- EventFiringWebDriver
在第一行中,我们将TakesScreenshot的一个实例初始化为ts
,并将WebDriver实例(即driver
)强制转换为该实例。
在第二行中,我们试图捕获屏幕截图并将其存储在指定的位置。对于WebDriver扩展TakesScreenshot
,这将根据浏览器(casted)的不同尽最大努力按首选顺序返回以下对象:
- 整个页面
- 当前窗口
- 当前帧的可见部分
- 包含浏览器的整个显示屏的屏幕截图
getScreenshotAs()
方法返回Object,其中包含有关屏幕截图的存储信息。失败时java.lang.UnsupportedOperationException
,这意味着底层实现不支持屏幕截图捕获机制。
您可以在此处找到详细文档。
参考
您可以在"如何使用Selenium WebDriver 进行屏幕截图"中找到详细的讨论
好吧,据我所知,这实际上不是一个特定于硒的问题,而是一个基本的Java问题。
您提供的表达式的含义:
((TakesScreenshot) driver).getScreenshotAs(OutputType.File)
如下:无论driver
变量的类型是什么,在这一行中,我们确信它实现了具有getScreenshotAs
方法的TakesScreenshot
接口。因此,我们将类型强制转换为TakesScreenshot
,并在driver
对象上调用getScreenshotAs
方法。这个方法的实现是在实际的driver
类中实现的,不管它是什么
给你一个非常接近问题代码的例子(我制作这个方法是为了接受Object
,所以我们真的需要将o
转换到目标接口。不要在真实代码中这样做):
public void log(Object o) {
((Printable) o).print();
}
其中Printable
是与方法print
:的一些接口
public interface Printable {
void print();
}
因此,如果我们有一些像一样的Printable
的实现
public class Greeting implements Printable {
@Override
public void print() {
System.out.println("Hello, username");
}
}
我们可以呼叫
log(new Greeting())
结果是行"你好,用户名">
编辑:
正如我在JavaDoc到selenium中看到的,WebDriver
接口并没有扩展TakesScreenshot
接口。因此,如果driver
变量的类型是WebDriver
接口,则必须强制转换它。WebDriver driver = new ChromeDriver()
-编译器只有WebDriver
类型的引用。尽管真正的类是ChromeDriver
,但编译器并不知道。因此,在这种情况下,为了调用getScreenshotAs
方法,您必须将driver
强制转换为TakesScreenshot
(这是安全的,因为driver
是ChromeDriver
的实例,它同时实现了WebDriver
和TakesScreenshot
接口)。之后才能从TakesScreenshot
接口调用getScreenshotAs
方法。
好吧,据我所知,这实际上不是一个硒特定的问题,而是一个基本的Java问题。
您提供的表达式的含义:
((TakesScreenshot) driver).getScreenshotAs(OutputType.File)
如下:无论driver
变量的类型是什么,在这一行中,我们确信它实现了具有getScreenshotAs
方法的TakesScreenshot
接口。因此,我们将类型强制转换为TakesScreenshot
,并在driver
对象上调用getScreenshotAs
方法。这个方法的实现是在真正的driver
类中实现的,不管它是什么
给你一个非常接近问题代码的例子(我制作这个方法是为了接受Object
,所以我们真的需要将o
转换到目标接口。不要在真实代码中这样做):
public void log(Object o) {
((Printable) o).print();
}
其中Printable
是与方法print
:的一些接口
public interface Printable {
void print();
}
所以如果我们有一些像一样的Printable
的实现
public class Greeting implements Printable {
@Override
public void print() {
System.out.println("Hello, username");
}
}
我们可以呼叫
log(new Greeting())
结果是行"你好,用户名">
编辑:
正如我在JavaDoc到selenium中看到的,WebDriver
接口并没有扩展TakesScreenshot
接口。因此,如果driver
变量的类型是WebDriver
接口,则必须强制转换它。WebDriver driver = new ChromeDriver()
-编译器只有WebDriver
类型的引用。尽管真正的类是ChromeDriver
,但编译器并不知道。因此,在这种情况下,为了调用getScreenshotAs
方法,您必须将driver
强制转换为TakesScreenshot
(这是安全的,因为driver
是ChromeDriver
的实例,它同时实现了WebDriver
和TakesScreenshot
接口)。之后才能从TakesScreenshot
接口调用getScreenshotAs
方法。
WebDriver driver = new ChromeDriver();
// driver.getScreenshotAs(OutputType.File); // compilation error as there is no method getScreenshotAs in WebDriver interface
((TakesScreenshot) driver).getScreenshotAs(OutputType.File); // ok after explicit casting