简体   繁体   English

如何抑制 Cucumber/Junit 断言堆栈跟踪

[英]How to suppress Cucumber/Junit assertion stack trace

I have a cucumber scenario and the step uses assertEquals .我有一个黄瓜场景,该步骤使用assertEquals My results report shows the stack trace which is not end user friendly.我的结果报告显示了对最终用户不友好的堆栈跟踪。 How can I suppress it我怎样才能压制它

  Scenario: Add two numbers
    Given I have two inputs "3" and "2"
    When I add them
    Then the output should be "15"

朱尼特

You're correct in observing that the default XML output (assuming you're not outputting to JSON or text, but you didn't say) from a Junit tests show stack traces for failed steps.您观察到来自 Junit 测试的默认 XML 输出(假设您没有输出到 JSON 或文本,但您没有说)显示失败步骤的堆栈跟踪是正确的。 This isn't actually a Cucumber thing.这实际上不是黄瓜的事情。 CucumberOptions won't help you here. CucumberOptions在这里帮不了你。

You can:你可以:

  1. Use a different or custom Runner for your test and then setup a tag that controls what is included in the output, or what will be read by the CI software of your choosing.为您的测试使用不同的或自定义的 Runner,然后设置一个标签来控制输出中包含的内容,或者您​​选择的CI 软件将读取的内容。 For example the Confulence API API for doing this tells how "debugger"例如,用于执行此操作的 Confulence API API 会告诉“调试器”如何
  2. Same type of deal for Ant Scripts to tweak the output, so that is doesn't show the output. Ant Scripts 调整输出的相同类型的交易,因此不会显示输出。 A good Tutorial for learning how to use Any scripts to fire off your Cucumber JUnit Test is here .学习如何使用 Any 脚本启动 Cucumber JUnit 测试的好教程在这里
  3. Other have build a custom formatter for JUnit by implementing XMLJUnitResultFormatter API , explained more here - How do I configure JUnit Ant task to only produce output on failures?其他人通过实现 XMLJUnitResultFormatter API为 JUnit 构建了一个自定义格式化程序,在这里解释了更多 - 如何配置 JUnit Ant 任务以仅在失败时生成输出?

Hope that gives you what you need.希望能给你你所需要的。

I was also facing same issue with my Cucumber-Selenium-Java project.我的 Cucumber-Selenium-Java 项目也面临同样的问题。 In the cucumber reports, it was generating around 40 lines of stacktrace.在黄瓜报告中,它生成了大约 40 行堆栈跟踪。 Due to this, it was impacting look and feel of the report.因此,它影响了报告的外观。 And the end user/client was little concerned about it.最终用户/客户对此并不关心。 Because he/she was not really able to figure out the actual use of this stacktrace.因为他/她无法真正弄清楚这个堆栈跟踪的实际用途。 So, I came up with below idea/approach.所以,我想出了以下想法/方法。 It's little bit tricky but, it's worthy.这有点棘手,但值得。

Few notes before starting:开始前的一些注意事项:

  1. We cannot completely disable stacktrace in in all the cases.我们不能在所有情况下完全禁用堆栈跟踪。 But we can modify the stacktrace and then, re-throw the new exception with useful and shortened stacktrace.但是我们可以修改堆栈跟踪,然后使用有用且缩短的堆栈跟踪重新抛出新异常。
  2. You need to be aware about frequently faced exceptions, errors.您需要了解经常遇到的异常、错误。 So that, we can create custom exception depending on the exceptions.因此,我们可以根据异常创建自定义异常。
  3. In the stacktrace it will generate few line of code from wrapper APIs, few lines from Junit/TestNg, few lines for java and selenium and there will be only one or two lines in the stacktrace, where actually our issue occurred.在堆栈跟踪中,它将从包装器 API 生成几行代码,从 Junit/TestNg 生成几行代码,为 java 和 selenium 生成几行代码,并且堆栈跟踪中只有一两行,实际上是我们的问题发生的地方。
  4. Our test classes must be in unique package.我们的测试类必须在唯一的包中。 So that, we can filter the stacktrace trace with package name and get the class name, line number and method name of actual issue and we can use this information in throwing custom exception.这样,我们可以使用包名过滤堆栈跟踪并获取实际问题的类名、行号和方法名,我们可以使用这些信息来抛出自定义异常。 Hence, it will be easy to figure out the actual line of issue occurred.因此,很容易找出实际发生的问题。 In my case all the classes were in package named "page".就我而言,所有类都在名为“page”的包中。 If you have more than one packages for your classes, then you can accordingly add string conditions in below code.如果你的类有多个包,那么你可以相应地在下面的代码中添加字符串条件。
  5. We need to wrap the test code in try-catch block.我们需要将测试代码包装在 try-catch 块中。 And while catching, we need to use Throwable class not exception class.在捕获时,我们需要使用 Throwable 类而不是异常类。 Because, if there is any assertion failure, then Exception class won't be able to handle the issue as you know all the assertions come under Error class and Throwable is the parent of Error and Exception.因为,如果有任何断言失败,那么 Exception 类将无法处理该问题,因为您知道所有断言都属于 Error 类,而 Throwable 是 Error 和 Exception 的父类。
  6. If we throw the new exception in catch block, then, it will change the line number in stacktrace, where actual issue occurred.如果我们在 catch 块中抛出新的异常,那么它会更改堆栈跟踪中实际发生问题的行号。 So it will be difficult to figure out the actual line of issue.因此,很难弄清楚问题的实际路线。 In order to avoid it, we need to get the class name, line number, method name of actual issue and store it in StackTraceElement class and use it in throwing new exception.为了避免它,我们需要获取实际问题的类名、行号、方法名并将其存储在 StackTraceElement 类中,并在抛出新异常时使用它。
  7. Some exceptions like "NoSuchElementException" provides lot of information in their cause and most of it is not really required, So we need to modify the content of it's message by using substring(), indexOf() and replaceAll() methods of String class in Java.像“NoSuchElementException”这样的异常提供了大量的原因信息,其中大部分并不是真正需要的,所以我们需要通过使用 String 类中的 substring()、indexOf() 和 replaceAll() 方法来修改它的消息内容爪哇。 And then, provide the modified information in new exception.然后,在新的异常中提供修改后的信息。
  8. Few important Java method from Throwable java class and their description: (i) getStackTrace(): This method will return us array of StackTraceElement class. Throwable java 类中的几个重要的Java 方法及其说明: (i) getStackTrace():该方法将返回StackTraceElement 类的数组。 StackTraceElement class will provide us the class name, method name, line number at which issue is occurred. StackTraceElement 类将为我们提供类名、方法名、发生问题的行号。 (ii) setStackTrace(): This method is used to provide a custom stacktrace to new Exception. (ii) setStackTrace():此方法用于为新异常提供自定义堆栈跟踪。 (iii) getCause(): This method will provide the issue message from cause of exception. (iii) getCause():此方法将提供来自异常原因的问题消息。 But sometimes, it might return null.但有时,它可能会返回 null。 Because for some exceptions "cause" might not be specified.因为对于某些例外,可能未指定“原因”。 So this needs be surround in try catch block and here we need to use getMessage() method for getting the actual error message.所以这需要包含在 try catch 块中,这里我们需要使用 getMessage() 方法来获取实际的错误消息。 (iv) getClass(): This method will return the actual exception class name. (iv) getClass():该方法将返回实际的异常类名。 We will use this method for figuring out the exception class name and then, we will use it for providing specific implementation for different different exception classes.我们将使用此方法来计算异常类名称,然后我们将使用它为不同的不同异常类提供具体的实现。 Note: "getClass()" method is not from "Throwable" class.注意:“getClass()”方法不是来自“Throwable”类。 It is from Object class.它来自 Object 类。

You need to create a common method for handling all the exceptions and reuse this method in all the required classes.您需要创建一个通用方法来处理所有异常,并在所有必需的类中重用此方法。 eg: I have named the method as "processException" and placed it in "ReusableMethod" class.例如:我将该方法命名为“processException”并将其放在“ReusableMethod”类中。

Note that, I am using package name "page" in below method (line#8), because all my test classes are placed in this package.请注意,我在下面的方法(第 8 行)中使用了包名“page”,因为我所有的测试类都放在这个包中。 In your case you need to update the package name as per your need.在您的情况下,您需要根据需要更新包名称。 Also, I have written custom cases for two exceptions only: NoSuchElementException & AssertionError.另外,我只为两个异常编写了自定义案例:NoSuchElementException 和 AssertionError。 You might need to write more cases as per your need.您可能需要根据需要编写更多案例。

public void processException(Throwable e) throws Exception {
        StackTraceElement[] arr = e.getStackTrace();
        String className = "";
        String methodName = "";
        int lineNumber = 0;
        for (int i = 0; i < arr.length; i++) {
            String localClassName = arr[i].getClassName();
            if (localClassName.startsWith("page")) {
                className = localClassName;
                methodName = arr[i].getMethodName();
                lineNumber = arr[i].getLineNumber();
                break;
            }
        }
        String cause = "";
        try {
            cause = e.getCause().toString();
        } catch (NullPointerException e1) {
            cause = e.getMessage();
        }
        StackTraceElement st = new StackTraceElement(className, methodName, "Line", lineNumber);
        StackTraceElement[] sArr = { st };
        if (e.getClass().getName().contains("NoSuchElementException")) {
            String processedCause = cause.substring(cause.indexOf("Unable to locate"), cause.indexOf("(Session info: "))
                    .replaceAll("\\n", "");
            Exception ex = new Exception("org.openqa.selenium.NoSuchElementException: " + processedCause);
            ex.setStackTrace(sArr);
            throw ex;
        } else if (e.getClass().getName().contains("AssertionError")) {
            AssertionError ae = new AssertionError(cause);
            ae.setStackTrace(sArr);
            throw ae;
        } else {
            Exception ex = new Exception(e.getClass() + ": " + cause);
            ex.setStackTrace(sArr);
            throw ex;
        }
    }

Below is the sample Method to showcase the usages of above method in Test Class methods.下面是示例方法,用于展示上述方法在测试类方法中的用法。 We are calling the above created method by using the class reference, which is "reuseMethod" in my case.我们通过使用类引用来调用上面创建的方法,在我的例子中是“reuseMethod”。 And we are passing the caught Throwable reference "e" to the above method in catch block:我们将捕获的 Throwable 引用“e”传递给 catch 块中的上述方法:

public void user_Navigates_To_Home_Page() throws Exception {
    try {
            //Certain lines of code as per your tests
            //element.click();
        } catch (Throwable e) {
            reuseMethod.processException(e); 
        }
  }

Here are few screenshots for implementation of NoSuchElementException:下面是一些实现 NoSuchElementException 的截图:

Before Implementing this approach:在实施此方法之前:

前

After Implementing this approach:实施此方法后:

后

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM