【问题标题】:Where is getScreenshotAs method defined?getScreenshotAs 方法在哪里定义?
【发布时间】:2018-03-19 15:59:09
【问题描述】:

我正在浏览 selenium 中的屏幕截图代码。下面是它的代码:

File src = ((TakesScreenshot)driver).getScreenshotAs(OutputType.File);

在上面一行中, TakesScreenshot 是一个接口,而 getScreenshotAs 是一个方法。所以我从中了解到的是,我们正在将驱动程序类型转换为 TakesScreenshot 接口,这本质上意味着我们的驱动程序从现在开始将表现得像 TakesScreenshot,之后将执行 getScreenshotAs 方法。

我的问题是接口只能有抽象方法。那么,getScreenshotAs 方法是如何通过 TakesScreenshot 接口执行的,因为它没有该方法的任何定义。更准确地说,getScreenshotAs 方法是在哪里定义的,上面这行代码是如何工作的?


添加更多细节:

TakeScreenshot --> 一个界面

driver --> ChromeDriver 类的实例 (WebDriver driver = new ChromeDriver())

getScreenshotAs --> TakesScreenshot 接口中的方法。

以上代码用于截取 selenium 中的网页截图。

【问题讨论】:

  • TakesScreenshot 和driver是什么,至少需要贴出部分代码
  • 你真正想知道的不清楚
  • 老兄,如果你知道 selenium,你就会知道这是截图的全部代码。
  • 但是,伙计,你不是在问硒问题。你是 ?您在问与 java 相关的问题
  • 我知道,但你的问题是关于执行的

标签: java selenium selenium-webdriver webdriver takesscreenshot


【解决方案1】:

首先让我分解你的代码进行解释:

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 有一个已知的 Subinterface 作为 WebElement。已知的实现类是:

  1. ChromeDriver
  2. Firefox 驱动程序
  3. InternetExplorerDriver
  4. EdgeDriver
  5. OperaDriver
  6. RemoteWebDriver
  7. RemoteWebElement`
  8. SafariDriver
  9. EventFiringWebDriver

在第一行中,我们将 TakesScreenshot 的实例初始化为 ts 并将 WebDriver 实例(即 driver)转换为该实例。

在第二行中,我们尝试捕获屏幕截图并将其存储在指定位置。对于扩展 TakesScreenshot 的 WebDriver,这将尽最大努力根据浏览器(强制转换)按优先顺序返回以下对象:

  1. 整个页面
  2. 当前窗口
  3. 当前帧的可见部分
  4. 包含浏览器的整个显示截图

getScreenshotAs() 方法返回存储截图信息的对象。失败时java.lang.UnsupportedOperationException,表示底层实现不支持截屏机制。

您可以找到详细文档here。


参考

您可以在How to take screenshot with Selenium WebDriver找到详细讨论

【讨论】:

    【解决方案2】:

    getScreenshotAs 方法在RemoteWebDriver 类中实现。你不能从你的driver 实例中使用它,因为你使用了WebDriver 接口,它没有扩展TakesScreenshot 接口,来创建driver 实例。

    投射到(或首先使用)RemoteWebDriver 或 ChromeDriver 也将允许您使用该方法。

    File src = ((RemoteWebDriver)driver).getScreenshotAs(OutputType.File);
    

    【讨论】:

      【解决方案3】:

      嗯,据我了解,这实际上不是一个特定于硒的问题,而是基本的 Java 问题。

      您提供的表达的含义:

      ((TakesScreenshot) driver).getScreenshotAs(OutputType.File)
      

      如下:无论driver变量的类型是什么,在这一行中我们确定它实现了TakesScreenshot接口,该接口具有getScreenshotAs方法。所以我们将类型转换为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 中看到的硒,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变量的类型是什么,在这一行中我们确定它实现了TakesScreenshot接口,该接口具有getScreenshotAs方法。所以我们将类型转换为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 中看到的硒,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
      

      【讨论】:

      • 感谢您的解释...但是如果 getScreenshotAs 方法的实现在我的主驱动程序类中,那么需要进行类型转换吗?
      • 如果driver 的类型与TakesScreenshot 接口及其实现不同(如我的示例中的Object o),则需要强制转换。如果在您的代码中driver 变量是TakesScreenshot driver 或TakesScreenshot 的任何实现类(例如ChromeDriver driver),您不需要强制转换并且可以直接在driver 变量上调用方法getScreenshotAs 。
      • 所以,本质上你是说如果我的驱动是ChromeDriver的一个实例,那么我可以直接写driver.getScreenshotAs,对吗?
      • 知道了..如果是这种情况,不知道为什么人们在使用 selenium 截屏之前先将驱动程序类型转换为 TakesScreenshot ..对此有什么猜测吗?
      • 我在我的答案中添加了一个编辑块(在澄清你的问题之后,我以前从未见过)
      猜你喜欢
      • 1970-01-01
      • 2017-07-02
      • 1970-01-01
      • 2012-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多