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

时间:2014-03-28 13:31:32

标签: java cucumber-jvm cucumber-junit

我有一个黄瓜场景,该步骤使用assertEquals。我的结果报告显示了最终用户友好的堆栈跟踪。我怎么能压制它

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

junit

2 个答案:

答案 0 :(得分:1)

您在观察默认XML输出时(假设您没有输出到JSON或文本,但您没有说过)来自Junit测试显示失败步骤的堆栈跟踪。这实际上不是黄瓜的东西。 CucumberOptions在这里不会帮助你。

你可以:

  1. 为测试使用不同的或自定义的Runner,然后设置一个标记,用于控制输出中包含的内容,或者您​​选择的CI software将要读取的内容。例如,用于执行此操作的Confulence API API会说明" debugger"
  2. Ant Scripts调整输出的相同类型的交易,因此不显示输出。学习如何使用任何脚本来启动Cucumber JUnit测试的好教程是here
  3. 其他人通过实现XMLJUnitResultFormatter API为JUnit构建自定义格式化程序,在此处解释更多 - How do I configure JUnit Ant task to only produce output on failures?
  4. 希望能满足您的需求。

答案 1 :(得分:1)

我的 Cucumber-Selenium-Java 项目也遇到了同样的问题。在黄瓜报告中,它生成了大约 40 行堆栈跟踪。因此,它影响了报告的外观。最终用户/客户对此并不关心。因为他/她无法真正弄清楚这个堆栈跟踪的实际用途。所以,我想出了以下想法/方法。这有点棘手,但值得。

开始前的一些注意事项:

  1. 我们无法在所有情况下完全禁用堆栈跟踪。但是我们可以修改堆栈跟踪,然后使用有用且缩短的堆栈跟踪重新抛出新异常。
  2. 您需要了解经常遇到的异常、错误。这样,我们就可以根据异常创建自定义异常。
  3. 在堆栈跟踪中,它将从包装器 API 生成几行代码,从 Junit/TestNg 生成几行代码,为 java 和 selenium 生成几行代码,并且堆栈跟踪中只有一两行代码,实际上是我们的问题发生的地方。< /li>
  4. 我们的测试类必须在唯一的包中。这样,我们可以使用包名过滤堆栈跟踪并获取实际问题的类名、行号和方法名,我们可以使用这些信息来抛出自定义异常。因此,很容易找出实际发生的问题。就我而言,所有类都在名为“page”的包中。如果你的类有多个包,那么你可以相应地在下面的代码中添加字符串条件。
  5. 我们需要将测试代码包装在 try-catch 块中。在捕获时,我们需要使用 Throwable 类而不是异常类。因为,如果有任何断言失败,那么 Exception 类将无法处理该问题,因为您知道所有断言都属于 Error 类,而 Throwable 是 Error 和 Exception 的父级。
  6. 如果我们在 catch 块中抛出新的异常,那么它会改变实际问题发生的堆栈跟踪中的行号。因此,很难弄清楚问题的实际路线。为了避免它,我们需要获取实际问题的类名、行号、方法名并将其存储在 StackTraceElement 类中,并在抛出新异常时使用。
  7. 像“NoSuchElementException”这样的异常在其原因中提供了很多信息,而其中大部分并不是真正必需的,因此我们需要使用 substring()、indexOf() 和 replaceAll() 方法来修改其消息的内容Java 中的字符串类。然后,在新的异常中提供修改后的信息。
  8. Throwable Java 类中的几个重要 Java 方法及其说明: (i) getStackTrace():该方法将返回 StackTraceElement 类的数组。 StackTraceElement 类将为我们提供类名、方法名、发生问题的行号。 (ii) setStackTrace():此方法用于为新异常提供自定义堆栈跟踪。 (iii) getCause():此方法将提供来自异常原因的问题消息。但有时,它可能会返回 null。因为对于某些例外,可能未指定“原因”。所以这需要包含在 try catch 块中,这里我们需要使用 getMessage() 方法来获取实际的错误消息。 (iv) getClass():该方法将返回实际的异常类名。我们将使用此方法来计算异常类名称,然后我们将使用它为不同的不同异常类提供具体的实现。注意:“getClass()”方法不是来自“Throwable”类。它来自 Object 类。

您需要创建一个通用方法来处理所有异常,并在所有必需的类中重用此方法。例如:我将该方法命名为“processException”并将其放在“ReusableMethod”类中。

请注意,我在下面的方法(第 8 行)中使用了包名“page”,因为我所有的测试类都放在这个包中。在您的情况下,您需要根据需要更新包名称。此外,我只为两个异常编写了自定义案例:NoSuchElementException 和 AssertionError。您可能需要根据需要编写更多案例。

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

下面是示例方法,用于展示上述方法在测试类方法中的用法。我们通过使用类引用来调用上面创建的方法,在我的例子中是“reuseMethod”。我们将捕获的 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); 
        }
  }

以下是 NoSuchElementException 实现的几个截图:

在实施此方法之前:

Before

实施此方法后:

After