如何在使用 JAVA 和 Cucumber 进行测试的每个步骤后捕获屏幕截图?
How to capture a screenshot after each step in tests with JAVA and Cucumber?
在 运行 集成测试时 在每个步骤后 捕获屏幕截图的最佳方式是什么?
使用 Selenium(3.0.1) 和 Cucumber(1.2.4) 在 Java 中编写测试。
下面是测试后截屏的代码,但我需要在每个方法后用@Given、@When、@Then 注释的截屏。
@After
public void after(Scenario scenario){
final byte[] screenshot = driver.getScreenshotAs(OutputType.BYTES);
scenario.embed(screenshot, "image/png");
}
感谢您的任何提示。
这个post对你有帮助吗?
Selenium 公开了一个名为 WebDriverEventListener 的接口,您可以实现自己的代码,通常此接口具有 afterFindBy 等方法,beforeFindBy 只需要实现该方法即可截屏。
实现此方法后,您需要将此实现的 class 注入驱动程序对象,如下所示
EventFiringWebDriver eventFiringWebDriver = new EventFiringWebDriver(driver);
MyWebDriverListerner handler = new MyWebDriverListerner();
eventFiringWebDriver.register(handler);
现在,只要驱动程序找到该元素,它就会调用相应的注入方法。
如果它解决了您的问题,请告诉我
这是您问题的答案:
假设您的方法如下:
@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());
}
如果这回答了您的问题,请告诉我。
在接受并合并以下合并请求之前,我认为这是不可能的。如果你真的感兴趣,你可以在本地合并它并拥有你自己的自定义 Jar。
这可能不是您要的,但这也可以帮助其他人! (虽然我没有用过 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();
}
}
}
}
}
}
cucumber 中没有 afterStep 注解 java。所以你不能直接做到这一点。您可以按照@DebanjanB 回答中提到的另一种方式进行操作。
但这可以在 cucumber-ruby 中通过后续步骤注释实现。
使用 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) { ....
}
}
}
此时,OP 可能已经想出了替代方案。但是,这可能会帮助其他人。最新版本io.cucumber同时具有@BeforeStep和@AfterStep,所以你可以在@AfterStep函数中只在一处嵌入截屏功能,解决你的问题。
在 运行 集成测试时 在每个步骤后 捕获屏幕截图的最佳方式是什么?
使用 Selenium(3.0.1) 和 Cucumber(1.2.4) 在 Java 中编写测试。
下面是测试后截屏的代码,但我需要在每个方法后用@Given、@When、@Then 注释的截屏。
@After
public void after(Scenario scenario){
final byte[] screenshot = driver.getScreenshotAs(OutputType.BYTES);
scenario.embed(screenshot, "image/png");
}
感谢您的任何提示。
这个post对你有帮助吗?
Selenium 公开了一个名为 WebDriverEventListener 的接口,您可以实现自己的代码,通常此接口具有 afterFindBy 等方法,beforeFindBy 只需要实现该方法即可截屏。
实现此方法后,您需要将此实现的 class 注入驱动程序对象,如下所示
EventFiringWebDriver eventFiringWebDriver = new EventFiringWebDriver(driver);
MyWebDriverListerner handler = new MyWebDriverListerner();
eventFiringWebDriver.register(handler);
现在,只要驱动程序找到该元素,它就会调用相应的注入方法。
如果它解决了您的问题,请告诉我
这是您问题的答案:
假设您的方法如下:
@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()); }
如果这回答了您的问题,请告诉我。
在接受并合并以下合并请求之前,我认为这是不可能的。如果你真的感兴趣,你可以在本地合并它并拥有你自己的自定义 Jar。
这可能不是您要的,但这也可以帮助其他人! (虽然我没有用过 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();
}
}
}
}
}
}
cucumber 中没有 afterStep 注解 java。所以你不能直接做到这一点。您可以按照@DebanjanB 回答中提到的另一种方式进行操作。
但这可以在 cucumber-ruby 中通过后续步骤注释实现。
使用 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) { ....
}
}
}
此时,OP 可能已经想出了替代方案。但是,这可能会帮助其他人。最新版本io.cucumber同时具有@BeforeStep和@AfterStep,所以你可以在@AfterStep函数中只在一处嵌入截屏功能,解决你的问题。