【问题标题】:How to capture a screenshot after each step in tests with JAVA and Cucumber?如何在使用 JAVA 和 Cucumber 进行测试的每个步骤后捕获屏幕截图?
【发布时间】:2017-06-01 04:02:13
【问题描述】:

在运行集成测试时,在每个步骤之后捕获屏幕截图的最佳方法是什么?

使用 Selenium(3.0.1) 和 Cucumber(1.2.4) 用 Ja​​va 编写测试。

测试后截屏的代码如下,但我需要在每个用@Given、@When、@Then注释的方法之后截屏。

@After
public void after(Scenario scenario){
    final byte[] screenshot = driver.getScreenshotAs(OutputType.BYTES);
    scenario.embed(screenshot, "image/png");
}

感谢您的任何提示。

【问题讨论】:

  • 你到底在用什么。在您的测试中,您说的是以下内容。 Selenium Protractor、Java、Cucumber 和你提到 Jasmine。这意味着 2 种语言(Java 和 JS)和 2 种框架(Cucumber 和 Jasmine)。如果您的意思是 CucumberJS 和 Protractor,请更改您的问题并提供您正在使用的 CucumberJS 和 Protractor 版本。然后我可以为您提供答案。
  • @wswebcreation 我已经更新了这个问题。感谢您的评论,我很困惑。
  • 我也更新了标题和标签,因为它是 Java 我帮不了你,我更像是一个 JS 人 ;-)。祝你好运
  • @wswebcreation 谢谢

标签: java selenium cucumber integration-testing


【解决方案1】:

使用 Aspects 解决了这个问题。非常棘手,请注意注释:

@After("call(public * cucumber.runtime.StepDefinitionMatch.runStep(..)) && within(cucumber.runtime.Runtime)")

下面是完整的代码,由 Viviana Cattenazzi 编写。

pom.xml

 <dependencies>
         <dependency>
             <groupId>org.aspectj</groupId>
             <artifactId>aspectjweaver</artifactId>
             <version>1.8.9</version>
         </dependency>
         <dependency>
             <groupId>org.aspectj</groupId>
             <artifactId>aspectjrt</artifactId>
             <version>1.8.9</version>
         </dependency>
         <dependency>
             <groupId>org.aspectj</groupId>
             <artifactId>aspectjtools</artifactId>
             <version>1.8.9</version>
         </dependency>
         <dependency>
             <groupId>info.cukes</groupId>
             <artifactId>cucumber-core</artifactId>
             <version>1.2.4</version>
         </dependency>
     </dependencies>

......

         <plugin>
             <groupId>org.codehaus.mojo</groupId>
             <artifactId>aspectj-maven-plugin</artifactId>
             <version>1.10</version>
             <configuration>
                 <weaveDependencies>
                     <weaveDependency>
                         <groupId>info.cukes</groupId>
                         <artifactId>cucumber-core</artifactId>
                     </weaveDependency>
                 </weaveDependencies>
                 <showWeaveInfo>true</showWeaveInfo>
                 <source>1.8</source>
                 <target>1.8</target>
                 <complianceLevel>1.8</complianceLevel>
             </configuration>
             <executions>
                 <execution>
                     <phase>process-test-classes</phase>
                     <goals>
                         <goal>compile</goal>
                         <goal>test-compile</goal>
                     </goals>
                 </execution>
             </executions>
         </plugin>

.......

StepsInterceptor.java

@Aspect
 public class StepsInterceptor {


     @After("call(public * cucumber.runtime.StepDefinitionMatch.runStep(..)) && within(cucumber.runtime.Runtime)")
     public void beforeRunningStep(JoinPoint thisJoinPoint) throws Exception {

         try {
             StepDefinitionMatch stepDefinitionMatch = (StepDefinitionMatch) thisJoinPoint.getTarget();
             Step step = (Step) retrievePrivateField(stepDefinitionMatch, "step");
             String stepName = step.getKeyword().trim();

             if ("Given".equals(stepName) || "When".equals(stepName)) {
                 Object theRealStepDef = extractJavaStepDefinition(stepDefinitionMatch);
                // take screen shot here
             }
         } catch (ClassCastException exc) { ....
}
}
}

【讨论】:

  • retrievePrivateField(..) 和 extractJavaStepDefinition(..) 方法的方法定义在哪里?
  • 可以发布 extractJavastepdefinition 和 retrievePrivateField 方法代码
  • @ttechen9: 我们应该把这段代码放在框架的什么地方?
【解决方案2】:

这篇文章对你有帮助吗?

Embedding screenshots in Cucumber JVM

【讨论】:

  • 这个有帮助,但只是测试后截图。
【解决方案3】:

这是您问题的答案:

  1. 假设您的方法如下:

    @Given("^Open$")
    public void Open() throws Throwable 
    {
        //your code
    }
    
    @When("^I$")
    public void I(String uname, String pass) throws Throwable 
    {
        //your code
    }
    
    @Then("^User$")
    public void User() throws Throwable 
    {
        //your code
    }
    
  2. 您可以编写一个库来截取屏幕截图,例如:

    public static void screenshot(WebDriver driver, long ms)
    {
    
    try {
        TakesScreenshot ts = (TakesScreenshot) driver;
        File source = ts.getScreenshotAs(OutputType.FILE);
        FileUtils.copyFile(source, new File("./ScreenShots/"+ms+"Facebook.png"));
        System.out.println("ScreenShot Taken");
    } 
    catch (Exception e) 
    {
        System.out.println("Exception while taking ScreenShot "+e.getMessage());
    }
    
    
    }
    
  3. 现在您可以在每个方法之后轻松调用该库来截取屏幕截图,如下所示:

    @Given("^Open$")
    public void Open() throws Throwable 
    {
        //your code
        Utility.screenshot(driver, System.currentTimeMillis());
    }
    
    @When("^I$")
    public void I(String uname, String pass) throws Throwable 
    {
        //your code
        Utility.screenshot(driver, System.currentTimeMillis());
    }
    
    @Then("^User$")
    public void User() throws Throwable 
    {
        //your code
        Utility.screenshot(driver, System.currentTimeMillis());
    }
    

如果这能回答您的问题,请告诉我。

【讨论】:

  • 感谢您的回答,但我有超过 600 种方法需要截屏。目前正在研究方面。
  • @tetchen9 太好了!!!恕我直言,当我没有其他选择时,我认为在 Java 中调用库没有任何问题。毫无疑问,Aspects 会是一个更好的选择,但您在构建问题时错过了提及您的基本要求。谢谢
  • @GaurangShah 你能考虑在你的评论中解释duplicate这个词吗?我一直相信libraries 是为了重用代码而编写的。谢谢
  • 但您建议在所有已编写的步骤和将要编写的所有新 stpes 中复制过去 Utility.screenshot(driver, System.currentTimeMillis()); 这段代码。这是多余的。它应该被自动调用。如前所述,该解决方案已在合并请求中可用。
  • @GaurangShah 我认为您遗漏了某些要点: 1. 我并没有声称我的答案是最好的解决方案。你也可以提供一个答案。 2. 随时欢迎您从 github 拉取并创建/构建自己的 exe/jar/解决方案,以帮助自己。 3. 这里 OP 提出了一个问题,我没有找到稳定且经过验证的 ListenerAnnotationtag 来解决 OP 的问题。因此,我简单地选择提供library 的概念。 4. 请求您维护一个有利于Stackoverflow全球社区的建设性环境
【解决方案4】:

我认为在接受并合并以下合并请求之前这是不可能的。如果你真的感兴趣,你可以在本地合并它并拥有自己的自定义 Jar。

https://github.com/cucumber/cucumber-jvm/pull/838

【讨论】:

    【解决方案5】:

    这可能不是您所要求的,但这也可以帮助其他人! (不过我没用过 Cucumber)

    这是我的代码,用于截取屏幕截图并将其添加到 PDF 文件中(如果你想用它做其他事情,你可以)。

    只要你想调用screenshotPDF(webDriver, testName)方法就行了!

    package com.helper;
    
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.List;
    
    import org.apache.commons.io.FileUtils;
    import org.apache.pdfbox.pdmodel.PDDocument;
    import org.apache.pdfbox.pdmodel.PDPage;
    import org.apache.pdfbox.pdmodel.PDPageContentStream;
    import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode;
    import org.apache.pdfbox.pdmodel.font.PDFont;
    import org.apache.pdfbox.pdmodel.font.PDType1Font;
    import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
    import org.openqa.selenium.Capabilities;
    import org.openqa.selenium.OutputType;
    import org.openqa.selenium.TakesScreenshot;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.WebDriverException;
    import org.openqa.selenium.remote.RemoteWebDriver;
    import org.openqa.selenium.remote.server.handler.WebDriverHandler;
    import org.testng.annotations.Test;
    
    public class ScreenshotPDF {
    
        @SuppressWarnings("deprecation")
        @Test
        //public static void screenshotPDF() {
        public static void screenshotPDF(WebDriver webDriver, String testName){
    
                    {
    
                PDDocument doc = null;
                boolean isNewFile = false;
    
                Date date = new Date();
                SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy h:mm:ss a");
                String timeStemp = sdf.format(date);
    
    
                try {
                    try {
                        doc = PDDocument.load(new File(
                                "C:/Users/Documents/sample.pdf"));
                    } catch (FileNotFoundException f) {
                        doc = new PDDocument();
                        PDPage p = new PDPage();
                        doc.addPage(p);
                        isNewFile = true;
                    }
    
                    File screenshot = ((TakesScreenshot) webDriver)
                            .getScreenshotAs(OutputType.FILE);
    
                    Integer numberP = doc.getNumberOfPages();
                    PDPage blankPage = new PDPage();
                    PDPage page;
                    if (!isNewFile) {
                        doc.addPage(blankPage);
                        page = doc.getPage(numberP);
                    } else { 
                        page = doc.getPage(numberP - 1);
                    }
                    PDImageXObject pdImage = PDImageXObject
                            .createFromFileByContent(screenshot, doc);
                    PDPageContentStream contentStream = new PDPageContentStream(
                            doc, page, AppendMode.APPEND, true);
                    PDFont font = PDType1Font.HELVETICA_BOLD;
                    contentStream.beginText();
                    contentStream.setFont(font, 12);
                    contentStream.moveTextPositionByAmount(100, 600);
                    contentStream.drawString(testName+"  "+timeStemp);
                    contentStream.endText();
    
                    float scale = 0.4f;
    
                    Capabilities cap = ((RemoteWebDriver) webDriver).getCapabilities();
                    String browserName = cap.getBrowserName().toLowerCase();
                    if (browserName.contains("explorer"))
                        scale = 0.4f;
    
                    contentStream.drawImage(pdImage, 50, 210, pdImage.getWidth() * scale, pdImage.getHeight() * scale);
                    contentStream.close();
                    contentStream.close();
                    doc.save("C:/Users/Documents/sample.pdf");
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (doc != null) {
                        try {
                            doc.close();
                        } catch (IOException e) {
    
                            e.printStackTrace();
                        }
                    }
                }
            }
    
        }
    
    }
    

    【讨论】:

      【解决方案6】:

      黄瓜java中没有afterStep注解。所以你不能直接做。您可以按照@DebanjanB 答案中提到的另一种方式进行操作。

      但这可以在 cucumber-ruby 中通过 after step 注释来实现。

      【讨论】:

        【解决方案7】:

        此时,OP 可能已经找到了替代方案。但是,这可能对其他人有所帮助。最新版本的 io.cucumber 同时具有@BeforeStep 和@AfterStep,因此您可以将屏幕截图捕获嵌入到@AfterStep 函数中的一个位置,从而解决您的问题。

        https://stackoverflow.com/a/53135127/5885718

        【讨论】:

          【解决方案8】:

          Selenium 暴露了一个叫做 WebDriverEventListener 的接口,你可以实现你自己的代码,一般这个接口有 afterFindBy 等方法,beforeFindBy 只需要实现那个方法来截屏。

          实现该方法后,您需要将该实现的类注入驱动对象,如下所示

          EventFiringWebDriver eventFiringWebDriver = new EventFiringWebDriver(driver);
              MyWebDriverListerner handler = new MyWebDriverListerner();
              eventFiringWebDriver.register(handler);
          

          现在,只要驱动程序找到该元素,它就会调用相应的注入方法。

          如果它解决了你的问题,请告诉我

          【讨论】:

          • OP需要截图after each method 不像afterFindBy(element)和beforeFindBy(elemnt)那样作为WebDriverEventListener的实现。谢谢
          猜你喜欢
          • 2018-10-28
          • 1970-01-01
          • 2015-04-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-05-03
          相关资源
          最近更新 更多