看了很多关于截屏文章。本来想着给每一个步骤截一个屏,但是这样一来存放截屏的文件夹就会非常大,所以,现在的方案是,用例运行失败之后截屏。

整个思路是:
1. 编写一个监听器RunTestListener,继承TestListenerAdapter
2. 该监听器里编辑运行失败了,执行截图操作
3. 运行配置testng.xml文件内,添加监听器

附上代码:

  1. 监听器RunTestListener
import io.appium.java_client.AppiumDriver;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.TestListenerAdapter;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Logger;

/**
 * Created by kuki_sini on 17/4/28.
 */
public class RunTestListener extends TestListenerAdapter {

    private AppiumDriver driver = Driver.getDriver();
    private static Logger logger = Logger.getLogger(RunTestListener.class.getName());

    @Override
    public void onTestFailure(ITestResult testResult) {
        super.onTestFailure(testResult);
        logger.info(testResult.getName() + " RunTestListener Failure");
        takeScreenShot(testResult);
    }

    /**
     * 自动截图
     *
     * @param testResult
     */
    private void takeScreenShot(ITestResult testResult) {
        System.out.println("截图");

        //时间格式化
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");

        //获取系统时间
        String currentTime = formatter.format(new Date());

        //获取screenshot文件
        File screenShot = driver.getScreenshotAs(OutputType.FILE);

        //截图命名
        String pictureName = currentTime + "_" + testResult.getName() + ".png";
        File dirFile = new File(System.getProperty("user.dir") + "/ScreenShot/" + pictureName);
        int i = 1;

        while (dirFile.exists()) {
            pictureName = currentTime + "_" + testResult.getName() + i + ".png";
            dirFile = new File(System.getProperty("user.dir") + "/ScreenShot/" + pictureName);
            i++;
        }

        //文件copy到指定文件夹
        try {
            FileUtils.copyFile(screenShot, dirFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
    } 
}
  1. 配置testng.xml文件,添加监听器元素
<listeners>
    <listener class-name="rl.utils.RunTestListener"/>
</listeners>
  1. feature 文件

这里我们就是用链家 APP(简称 LJ)来做实验哈

Feature: 调试使用

  Scenario: LJ启动
    Given 链家APP启动
    When 在首页界面上点击`我要租房`按钮
    Then 校验是否正确进入租房画面

  Scenario Outline: 调试
    When 选择<选项>按钮
    Then 校验<校验>画面是否正确打开

    Examples:
      | 选项   | 校验|
      | 特殊租房 | 特殊租房  |

  Scenario: 进入看房履历功能
    When 在下方工具栏处点击看房按钮

  Scenario: 结束LJ
    But LJ关闭

这样看似完了,完全没错嘛。但是,问题来了,这与我们的初衷有点不同。
上面的代码,如果某一Scenario的某一Step失败了,那就需要等到整个Feature运行完了才会开始执行截屏,而不是我们想象的那样Step运行失败了紧接着立马就截屏。

实际上,特殊租房这个功能没有,所以,在第二个Scenario他就会运行失败,理论上就需要截屏。实际上是没有的,运行结果报错了

五月 03, 2017 4:51:58 下午 rl.utils.RunTestListener onFinish
信息: test RunTestListener Finish
org.openqa.selenium.WebDriverException: Method has not yet been implemented (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 13 milliseconds
Build info: version: '2.53.1', revision: 'a36b8b1cd5757287168e54b817830adce9b0158d', time: '2016-06-30 19:26:09'
System info: host: 'binlis-Mac-mini.local', ip: '192.168.1.153', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.12.4', java.version: '1.8.0_77'
Driver info: io.appium.java_client.ios.IOSDriver
Capabilities [{app=/Applications/autotest/testAutomation/apps/LJ.app, networkConnectionEnabled=false, noReset=true, databaseEnabled=false, deviceName=autotest02, launchTimeout=500000, platform=MAC, platformVersion=10.3.1, webStorageEnabled=false, locationContextEnabled=false, automationName=XCuiTest, browserName=, takesScreenshot=true, javascriptEnabled=true, udid=3aa77f1ec16222b06cc5481ee3e51f941b758d04, platformName=iOS}]
Session ID: 11d2726f-0197-47d2-90e0-3664d183a44d
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:206)
    at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:158)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:678)
    at io.appium.java_client.DefaultGenericMobileDriver.execute(DefaultGenericMobileDriver.java:40)
    at io.appium.java_client.AppiumDriver.execute(AppiumDriver.java:235)
    at org.openqa.selenium.remote.RemoteWebDriver.getScreenshotAs(RemoteWebDriver.java:335)
    at rl.utils.RunTestListener.takeScreenShot(RunTestListener.java:74)
    at rl.utils.RunTestListener.onTestFailure(RunTestListener.java:35)
    at org.testng.internal.Invoker.runTestListeners(Invoker.java:1691)
    at org.testng.internal.Invoker.runTestListeners(Invoker.java:1675)
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1183)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:129)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:112)
    at org.testng.TestRunner.privateRun(TestRunner.java:782)
    at org.testng.TestRunner.run(TestRunner.java:632)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:366)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:361)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:319)
    at org.testng.SuiteRunner.run(SuiteRunner.java:268)
    at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
    at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
    at org.testng.TestNG.runSuitesSequentially(TestNG.java:1244)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:1169)
    at org.testng.TestNG.run(TestNG.java:1064)
    at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:72)
    at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:127)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

Process finished with exit code 0

但是如果将Scenario: 结束LJ But LJ关闭注释掉,运行没有问题,截屏功能没有问题。但是截的图却是最后一个Scenario的最后一个步骤

这个不解呀,为啥会这样呢,还望各位童鞋了帮忙看看


↙↙↙阅读原文可查看相关链接,并与作者交流