Question

I have a cucumber scenario and the step uses 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"

junit

Était-ce utile?

La solution

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. This isn't actually a Cucumber thing. CucumberOptions won't help you here.

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. For example the Confulence API API for doing this tells how "debugger"
  2. Same type of deal for Ant Scripts to tweak the output, so that is doesn't show the output. A good Tutorial for learning how to use Any scripts to fire off your Cucumber JUnit Test is here.
  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?

Hope that gives you what you need.

Autres conseils

I was also facing same issue with my Cucumber-Selenium-Java project. In the cucumber reports, it was generating around 40 lines of stacktrace. 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.
  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". 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. And while catching, we need to use Throwable class not exception class. 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.
  6. If we throw the new exception in catch block, then, it will change the line number in stacktrace, where actual issue occurred. 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.
  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. 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. StackTraceElement class will provide us the class name, method name, line number at which issue is occurred. (ii) setStackTrace(): This method is used to provide a custom stacktrace to new Exception. (iii) getCause(): This method will provide the issue message from cause of exception. But sometimes, it might return 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. (iv) getClass(): This method will return the actual exception class name. 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. It is from Object class.

You need to create a common method for handling all the exceptions and reuse this method in all the required classes. e.g.: I have named the method as "processException" and placed it in "ReusableMethod" class.

Note that, I am using package name "page" in below method (line#8), because all my test classes are placed in this package. 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. 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. And we are passing the caught Throwable reference "e" to the above method in catch block:

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:

Before Implementing this approach:

Before

After Implementing this approach:

After

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top