如何在使用 JAVA 和 Cucumber 进行测试的每个步骤后捕获屏幕截图?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/44298345/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to capture a screenshot after each step in tests with JAVA and Cucumber?
提问by tetchen9
What would be the best way to capture screenshots after each stepwhen running integration tests?
在运行集成测试时,在每个步骤之后捕获屏幕截图的最佳方法是什么?
Tests are written in Java using Selenium(3.0.1) and Cucumber(1.2.4).
测试是使用 Selenium(3.0.1) 和 Cucumber(1.2.4) 用 Java 编写的。
Code for taking a screenshot after a test is below, but I need a screenshot after each method annotated with @Given, @When, @Then.
下面是在测试后截取屏幕截图的代码,但我需要在每个用@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.
谢谢你的任何提示。
采纳答案by tetchen9
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.
以下是 Viviana Cattenazzi 编写的完整代码。
pom.xml
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
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) { ....
}
}
}
回答by wswebcreation
回答by DebanjanB
Here is the Answer to your Question:
以下是您问题的答案:
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 }
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()); } }
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()); }
让我们假设您的方法如下:
@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 }
您可以编写一个库来截取屏幕截图,例如:
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()); } }
现在您可以在每个方法后轻松调用库来截取屏幕截图,如下所示:
@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.
如果这能回答您的问题,请告诉我。
回答by Gaurang Shah
I don't think it would be possible until following merge request is accepted and merged. if you are really interested you can merge it locally and have your own custom Jar.
我认为在接受并合并以下合并请求之前这是不可能的。如果您真的有兴趣,可以在本地合并它并拥有自己的自定义 Jar。
回答by R Dhaval
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).
这是我的代码,用于截取屏幕并将其添加到 PDF 文件中(如果您想用它做其他事情,您可以)。
Just you have to call screenshotPDF(webDriver, testName)
method whenever you want!
只是你必须随时调用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();
}
}
}
}
}
}
回答by Murthi
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.
黄瓜 java 中没有 afterStep 注释。所以你不能一蹴而就。你可以用@DebanjanB 回答中提到的另一种方式来做。
But this can be achievable in cucumber-ruby with after step annotation.
但这可以在带有 after step 注释的 Cucumber-ruby 中实现。
回答by Bhuvanesh Mani
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.
此时,OP 可能已经找到了替代选项。然而,这可能会帮助其他人。最新版本的io.cucumber 同时包含@BeforeStep 和@AfterStep,因此您可以将截屏嵌入到@AfterStep 函数中,只需在一处即可解决您的问题。
回答by Manoj G
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.
Selenium 公开了一个名为 WebDriverEventListener 的接口,您可以实现自己的代码,通常该接口具有 afterFindBy 等方法,beforeFindBy 只需要实现该方法即可截取屏幕截图。
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
让我知道它是否能解决您的问题