How to capture a screenshot after each step in tes

2020-02-01 06:13发布

What would be the best way to capture screenshots after each step when running integration tests?

Tests are written in Java using Selenium(3.0.1) and Cucumber(1.2.4).

Code for taking a screenshot after a test is below, but I need a screenshot after each method annotated with @Given, @When, @Then.

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

Thank you for any hints.

8条回答
干净又极端
2楼-- · 2020-02-01 06:41

Here is the Answer to your Question:

  1. Lets assume your methods are as follows:

    @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. You can write a library to take screenshots like:

    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. Now you can easily call the library after every method to take the screenshot as follows:

    @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());
    }
    

Let me know if this Answers your Question.

查看更多
我想做一个坏孩纸
3楼-- · 2020-02-01 06:43

Selenium exposed a interfaced called as WebDriverEventListener, which you can implement you own code generally this interface has methods like afterFindBy , beforeFindBy just need to implement that method to take screen shots.

After implementing this method then you need to inject this implemented class to driver object as shown below

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

Now whenever driver finds the element then it will invoke that respective injected method.

Let me know if it solves your problem

查看更多
迷人小祖宗
4楼-- · 2020-02-01 06:46

There is no afterStep annotation in cucumber java. So you cann't do it in straight forward. You can do it in another way as mentioned in @DebanjanB answer.

But this can be achievable in cucumber-ruby with after step annotation.

查看更多
狗以群分
5楼-- · 2020-02-01 06:50

Solved this using Aspects. Was pretty tricky, note the annotation:

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

Below is the full code, written by 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) { ....
}
}
}
查看更多
Bombasti
6楼-- · 2020-02-01 06:50

This might not be what you asked but this can help others too! (I haven't used Cucumber though)

Here is my code to take a screen shot and add it to a PDF file (If you want to do something else with it that you can).

Just you have to call screenshotPDF(webDriver, testName) method whenever you want!

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();
                    }
                }
            }
        }

    }

}
查看更多
够拽才男人
7楼-- · 2020-02-01 06:52

At this time, OP might have figured out alternative options. However this may help others. Latest version of io.cucumber has both @BeforeStep and @AfterStep, so you can embed screenshot capturing in to @AfterStep function at only one place which solves your problem.

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

查看更多
登录 后发表回答