com.stratio.qa.cucumber.testng.CucumberReporter.java Source code

Java tutorial

Introduction

Here is the source code for com.stratio.qa.cucumber.testng.CucumberReporter.java

Source

/*
 * Copyright (C) 2014 Stratio (http://stratio.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.stratio.qa.cucumber.testng;

import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathNotFoundException;
import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.Response;
import com.stratio.qa.specs.CommonG;
import com.stratio.qa.utils.ThreadProperty;
import cucumber.runtime.CucumberException;
import cucumber.runtime.Utils;
import cucumber.runtime.io.URLOutputStream;
import cucumber.runtime.io.UTF8OutputStreamWriter;
import gherkin.formatter.Formatter;
import gherkin.formatter.Reporter;
import gherkin.formatter.model.*;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.*;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class CucumberReporter implements Formatter, Reporter {

    public static final int DURATION_STRING = 1000000;

    public static final int DEFAULT_LENGTH = 11;

    public static final int DEFAULT_MAX_LENGTH = 140;

    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");

    private static final String STATUS = "status";

    private final Document document;

    private final Document jUnitDocument;

    private final Element results;

    private final Element jUnitResults;

    private final Element suite;

    private final Element jUnitSuite;

    private final Element test;

    private String featureName;

    private Writer writer;

    private Writer writerJunit;

    private Element clazz;

    private Element root;

    private Element jUnitRoot;

    private TestMethod testMethod;

    private Examples tmpExamples;

    private List<Result> tmpHooks = new ArrayList<Result>();

    private List<Step> tmpSteps = new ArrayList<Step>();

    private List<Step> tmpStepsBG = new ArrayList<Step>();

    private Integer iteration = 0;

    private Integer position = 0;

    private String callerClass;

    private Background background;

    private String url;

    private String cClass;

    private String additional;

    private final Logger logger = LoggerFactory.getLogger(this.getClass().getCanonicalName());

    /**
     * Constructor of cucumberReporter.
     *
     * @param url url
     * @param cClass class
     * @throws IOException exception
     */
    public CucumberReporter(String url, String cClass, String additional) throws IOException {
        this.url = url;
        this.cClass = cClass;
        this.additional = additional;

        try {
            document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
            results = document.createElement("testng-results");
            suite = document.createElement("suite");
            test = document.createElement("test");
            callerClass = cClass;
            suite.appendChild(test);
            results.appendChild(suite);
            document.appendChild(results);
            jUnitDocument = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
            jUnitResults = jUnitDocument.createElement("testsuites");
            jUnitSuite = jUnitDocument.createElement("testsuite");
            jUnitDocument.appendChild(jUnitResults);
            jUnitResults.appendChild(jUnitSuite);
        } catch (ParserConfigurationException e) {
            throw new CucumberException("Error initializing DocumentBuilder.", e);
        }
    }

    @Override
    public void syntaxError(String state, String event, List<String> legalEvents, String uri, Integer line) {
    }

    @Override
    public void uri(String uri) {
    }

    @Override
    public void feature(Feature feature) {
        featureName = feature.getName();
        clazz = document.createElement("class");
        clazz.setAttribute("name", callerClass);
        test.appendChild(clazz);
    }

    @Override
    public void scenario(Scenario scenario) {
    }

    @Override
    public void scenarioOutline(ScenarioOutline scenarioOutline) {
        iteration = 1;
    }

    @Override
    public void examples(Examples examples) {
        tmpExamples = examples;
    }

    @Override
    public void startOfScenarioLifeCycle(Scenario scenario) {
        root = document.createElement("test-method");
        jUnitRoot = jUnitDocument.createElement("testcase");
        jUnitSuite.appendChild(jUnitRoot);
        clazz.appendChild(root);
        testMethod = new TestMethod(featureName, scenario);
        testMethod.hooks = tmpHooks;
        tmpStepsBG.clear();
        if (tmpExamples == null) {
            testMethod.steps = tmpSteps;
            testMethod.stepsbg = null;
        } else {
            testMethod.steps = new ArrayList<Step>();
            testMethod.stepsbg = tmpStepsBG;
        }
        testMethod.examplesData = tmpExamples;
        testMethod.start(root, iteration, jUnitRoot);
        iteration++;
    }

    @Override
    public void background(Background background) {
        this.background = background;
    }

    @Override
    public void step(Step step) {
        boolean bgstep = false;
        if (background != null && (background.getLineRange().getLast() <= step.getLine())
                && (step.getLine() >= background.getLineRange().getFirst())) {
            tmpStepsBG.add(step);
            bgstep = true;
        }

        if (step.getClass().toString().contains("ExampleStep") && !bgstep) {
            testMethod.steps.add(step);
        } else {
            tmpSteps.add(step);
        }
    }

    @Override
    public void endOfScenarioLifeCycle(Scenario scenario) {

        try {
            testMethod.finish(document, root, this.position, scenario.getTags(), jUnitDocument, jUnitRoot);
        } catch (ExecutionException | InterruptedException | IOException e) {
            e.printStackTrace();
        }

        this.position++;
        if ((tmpExamples != null) && (iteration >= tmpExamples.getRows().size())) {
            tmpExamples = null;
        }
        tmpHooks.clear();
        tmpSteps.clear();
        tmpStepsBG.clear();
        testMethod = null;
        jUnitRoot.setAttribute("classname", callerClass);
    }

    @Override
    public void eof() {
    }

    @Override
    public void done() {
        try {
            results.setAttribute("total", String.valueOf(getElementsCountByAttribute(suite, STATUS, ".*")));
            results.setAttribute("passed", String.valueOf(getElementsCountByAttribute(suite, STATUS, "PASS")));
            results.setAttribute("failed", String.valueOf(getElementsCountByAttribute(suite, STATUS, "FAIL")));
            results.setAttribute("skipped", String.valueOf(getElementsCountByAttribute(suite, STATUS, "SKIP")));
            suite.setAttribute("name", CucumberReporter.class.getName());
            suite.setAttribute("duration-ms",
                    String.valueOf(getTotalDuration(suite.getElementsByTagName("test-method"))));
            test.setAttribute("name", CucumberReporter.class.getName());
            test.setAttribute("duration-ms",
                    String.valueOf(getTotalDuration(suite.getElementsByTagName("test-method"))));
            Transformer transformer = TransformerFactory.newInstance().newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");

            URLOutputStream urlOS = null;
            try {
                urlOS = new URLOutputStream(Utils.toURL(url + cClass + additional + "TESTNG.xml"));
                this.writer = new UTF8OutputStreamWriter(urlOS);
            } catch (Exception e) {
                logger.error("error writing TESTNG.xml file", e);
            }

            StreamResult streamResult = new StreamResult(writer);
            DOMSource domSource = new DOMSource(document);
            transformer.transform(domSource, streamResult);
            jUnitSuite.setAttribute("name", callerClass + "." + featureName);
            jUnitSuite.setAttribute("tests", String.valueOf(getElementsCountByAttribute(suite, STATUS, ".*")));
            jUnitSuite.setAttribute("failures", String.valueOf(getElementsCountByAttribute(suite, STATUS, "FAIL")));
            jUnitSuite.setAttribute("skipped", String.valueOf(getElementsCountByAttribute(suite, STATUS, "SKIP")));
            jUnitSuite.setAttribute("timestamp", new java.util.Date().toString());
            jUnitSuite.setAttribute("time",
                    String.valueOf(getTotalDurationMs(suite.getElementsByTagName("test-method"))));
            Transformer transformerJunit = TransformerFactory.newInstance().newTransformer();
            transformerJunit.setOutputProperty(OutputKeys.INDENT, "yes");

            try {
                urlOS = new URLOutputStream(Utils.toURL(url + cClass + additional + "JUNIT.xml"));
                this.writerJunit = new UTF8OutputStreamWriter(urlOS);
            } catch (Exception e) {
                logger.error("error writing TESTNG.xml file", e);
            }

            StreamResult streamResultJunit = new StreamResult(writerJunit);
            DOMSource domSourceJunit = new DOMSource(jUnitDocument);
            transformerJunit.transform(domSourceJunit, streamResultJunit);

        } catch (TransformerException e) {
            throw new CucumberException("Error transforming report.", e);
        }
    }

    @Override
    public void close() {
    }

    // Reporter methods
    @Override
    public void before(Match match, Result result) {
        tmpHooks.add(result);
    }

    @Override
    public void match(Match match) {
    }

    @Override
    public void result(Result result) {
        testMethod.results.add(result);
    }

    @Override
    public void embedding(String mimeType, byte[] data) {
    }

    @Override
    public void write(String text) {
    }

    @Override
    public void after(Match match, Result result) {
        testMethod.hooks.add(result);
    }

    private int getElementsCountByAttribute(Node node, String attributeName, String attributeValue) {
        int count = 0;

        for (int i = 0; i < node.getChildNodes().getLength(); i++) {
            count += getElementsCountByAttribute(node.getChildNodes().item(i), attributeName, attributeValue);
        }

        NamedNodeMap attributes = node.getAttributes();
        if (attributes != null) {
            Node namedItem = attributes.getNamedItem(attributeName);
            if (namedItem != null && namedItem.getNodeValue().matches(attributeValue)) {
                count++;
            }
        }
        return count;
    }

    private double getTotalDuration(NodeList testCaseNodes) {
        double totalDuration = 0;
        for (int i = 0; i < testCaseNodes.getLength(); i++) {
            try {
                String duration = "0";
                Node durationms = testCaseNodes.item(i).getAttributes().getNamedItem("duration-ms");
                if (durationms != null) {
                    duration = durationms.getNodeValue();
                }
                totalDuration += Double.parseDouble(duration);
            } catch (NumberFormatException e) {
                throw new CucumberException(e);
            }
        }
        return totalDuration;
    }

    private double getTotalDurationMs(NodeList testCaseNodes) {
        return getTotalDuration(testCaseNodes) / 1000;
    }

    public final class TestMethod {

        private boolean treatSkippedAsFailure = false;

        private final List<Result> results = new ArrayList<Result>();

        private Scenario scenario = null;

        private String featureName;

        private Examples examplesData;

        private List<Step> steps;

        private List<Step> stepsbg;

        private List<Result> hooks;

        private Integer iteration = 1;

        public TestMethod(String feature, Scenario scenario) {
            this.featureName = feature;
            this.scenario = scenario;
        }

        private void start(Element element, Integer iteration, Element JunitElement) {
            this.iteration = iteration;
            String testSuffix = System.getProperty("TESTSUFFIX");
            String name = scenario.getName();
            if (testSuffix != null) {
                name = name + " [" + testSuffix + "]";
            }
            if ((examplesData == null) || (this.iteration >= examplesData.getRows().size())) {
                element.setAttribute("name", name);
                JunitElement.setAttribute("name", name);
                ThreadProperty.set("dataSet", "");
            } else {
                String data = obtainOutlineScenariosExamples(
                        examplesData.getRows().get(iteration).getCells().toString());
                element.setAttribute("name", name + " " + data);
                JunitElement.setAttribute("name", name + " " + data);
                ThreadProperty.set("dataSet", data);
            }
            element.setAttribute("started-at", DATE_FORMAT.format(new Date()));
        }

        public String obtainOutlineScenariosExamples(String examplesData) {
            String data = examplesData.replaceAll("\"", "");
            return data;
        }

        /**
         * Checks the passed by ticket parameter validity against a Attlasian Jira account
         *
         * @param ticket Jira ticket
         */
        private boolean isValidJiraTicket(String ticket) {
            String userJira = System.getProperty("usernamejira");
            String passJira = System.getProperty("passwordjira");
            Boolean validTicket = false;

            if ((userJira != null) || (passJira != null) || "".equals(ticket)) {
                CommonG comm = new CommonG();
                AsyncHttpClient client = new AsyncHttpClient();
                Future<Response> response = null;
                Logger logger = LoggerFactory.getLogger(ThreadProperty.get("class"));

                comm.setRestProtocol("https://");
                comm.setRestHost("stratio.atlassian.net");
                comm.setRestPort("");
                comm.setClient(client);
                String endpoint = "/rest/api/2/issue/" + ticket;
                try {
                    response = comm.generateRequest("GET", true, userJira, passJira, endpoint, "", "json");
                    comm.setResponse(endpoint, response.get());
                } catch (Exception e) {
                    logger.error(
                            "Rest API Jira connection error " + String.valueOf(comm.getResponse().getStatusCode()));
                    return false;
                }

                String json = comm.getResponse().getResponse();
                String value = "";
                try {
                    value = JsonPath.read(json, "$.fields.status.name");
                    value = value.toLowerCase();
                } catch (PathNotFoundException pe) {
                    logger.error("Json Path $.fields.status.name not found\r");
                    logger.error(json);
                    return false;
                }

                if (!"done".equals(value) || !"finalizado".equals(value) || !"qa".equals(value)) {
                    validTicket = true;
                }
            }
            return validTicket;
        }

        /**
         * Builds a test result xml document, builds exception messages on non valid ignore causes such as
         * \@tillfixed without an in progress Stratio's Jira ticker
         *
         * @param doc report document
         * @param element scenario execution result
         * @param position position of element in document
         * @param tags tags that performs conditional inclusion of element
         * @param docJunit docJunit report document
         * @param Junit Junit scenario execution result
         * @throws ExecutionException exception
         * @throws InterruptedException exception
         * @throws IOException exception
         */
        public void finish(Document doc, Element element, Integer position, List<Tag> tags, Document docJunit,
                Element Junit) throws ExecutionException, InterruptedException, IOException {

            Junit.setAttribute("time", String.valueOf(calculateTotalDurationString() / 1000));

            element.setAttribute("duration-ms", String.valueOf(calculateTotalDurationString()));
            element.setAttribute("finished-at", DATE_FORMAT.format(new Date()));

            StringBuilder stringBuilder = new StringBuilder();

            List<Step> mergedsteps = new ArrayList<Step>();
            if (stepsbg != null) {
                mergedsteps.addAll(stepsbg);
                mergedsteps.addAll(steps);
            } else {
                mergedsteps.addAll(steps);
            }
            addStepAndResultListing(stringBuilder, mergedsteps);
            Result skipped = null;
            Result failed = null;
            Boolean ignored = false;
            Boolean ignoreReason = false;
            String exceptionmsg = "Failed";
            String ticket = "";
            Boolean isJiraTicketDone = false;
            Boolean isWrongTicket = false;
            Boolean ignoreRun = false;

            List<String> tagList = new ArrayList<>();
            tagList = tags.stream().map(Tag::getName).collect(Collectors.toList());

            if (tagList.contains("@ignore")) {
                ignored = true;
                for (String tag : tagList) {
                    Pattern pattern = Pattern.compile("@tillfixed\\((.*?)\\)");
                    Matcher matcher = pattern.matcher(tag);
                    if (matcher.find()) {
                        ticket = matcher.group(1);
                        if (isValidJiraTicket(ticket)) {
                            exceptionmsg = "This scenario was skipped because of a pending Jira ticket: " + ticket;
                            ignoreReason = true;
                        }
                        break;
                    }
                }

                if (tagList.contains("@unimplemented")) {
                    exceptionmsg = "This scenario was skipped because of it is not yet implemented";
                    ignoreReason = true;
                }

                if (tagList.contains("@manual")) {
                    ignoreReason = true;
                    exceptionmsg = "This scenario was skipped because it is marked as manual.";
                }

                if (tagList.contains("@toocomplex")) {
                    exceptionmsg = "This scenario was skipped because of being too complex to test";
                    ignoreReason = true;
                }

                if (tagList.contains("@envCondition")) {
                    ignoreRun = true;
                }
            }

            String msg1 = "";
            String msg2 = "";

            if (ignoreRun) {
                docJunit.getDocumentElement().getLastChild()
                        .removeChild(docJunit.getDocumentElement().getLastChild().getLastChild());
                return;
            } else if (ignored
                    && (!ignoreReason || (ignoreReason && isJiraTicketDone) || (ignoreReason && isWrongTicket))) {
                element.setAttribute(STATUS, "FAIL");
                if (isJiraTicketDone) {
                    msg1 = "The scenario was ignored due an already done (or in progress) ticket. "
                            + "https://stratio.atlassian.net/browse/" + ticket;
                } else if (isWrongTicket) {
                    msg1 = "The scenario was ignored due to unexistant ticket " + ticket;
                } else {
                    msg1 = "The scenario has no valid reason for being ignored. \n Valid values: @tillfixed(ISSUE-007) @unimplemented @manual @toocomplex";
                }

                Element exception = createException(doc, msg1, msg1, msg2);
                element.appendChild(exception);
                Element systemOut = createExceptionJunit(docJunit, msg1, msg1, msg2);
                Junit.appendChild(systemOut);

            } else if (ignored && ignoreReason) {
                element.setAttribute(STATUS, "SKIP");
                Element exception = createException(doc, "skipped", exceptionmsg, " ");
                element.appendChild(exception);
                Element skippedElementJunit = docJunit.createElement("skipped");
                Junit.appendChild(skippedElementJunit);
                Element systemOut = systemOutPrintJunit(docJunit, exceptionmsg);
                Junit.appendChild(systemOut);

            } else if ((stringBuilder.toString().contains("${")) || (stringBuilder.toString().contains("!{"))
                    || (stringBuilder.toString().contains("@{"))) {
                element.setAttribute(STATUS, "FAIL");
                Element exception = createException(doc, "The scenario has unreplaced variables.",
                        "The scenario has unreplaced variables.", " ");
                element.appendChild(exception);
                Element exceptionJunit = createExceptionJunit(docJunit, "The scenario has unreplaced variables.",
                        "The scenario has unreplaced variables.", " ");
                Junit.appendChild(exceptionJunit);
                Element systemOut = systemOutPrintJunit(docJunit, stringBuilder.toString());
                Junit.appendChild(systemOut);
            } else {
                for (Result result : results) {
                    if ("failed".equals(result.getStatus())) {
                        failed = result;
                    } else if ("undefined".equals(result.getStatus()) || "pending".equals(result.getStatus())) {
                        skipped = result;
                    }
                }
                for (Result result : hooks) {
                    if (failed == null && "failed".equals(result.getStatus())) {
                        failed = result;
                    }
                }
                if (failed != null) {
                    element.setAttribute(STATUS, "FAIL");
                    StringWriter stringWriter = new StringWriter();
                    failed.getError().printStackTrace(new PrintWriter(stringWriter));
                    Element exception = createException(doc, failed.getError().getClass().getName(),
                            stringBuilder.toString(), stringWriter.toString());
                    element.appendChild(exception);
                    Element exceptionJunit = createExceptionJunit(docJunit, failed.getError().getClass().getName(),
                            stringBuilder.toString(), stringWriter.toString());
                    Junit.appendChild(exceptionJunit);
                } else if (skipped != null) {
                    if (treatSkippedAsFailure) {
                        element.setAttribute(STATUS, "FAIL");
                        Element exception = createException(doc, "The scenario has pending or undefined step(s)",
                                stringBuilder.toString(), "The scenario has pending or undefined step(s)");
                        element.appendChild(exception);
                        Element exceptionJunit = createExceptionJunit(docJunit,
                                "The scenario has pending or undefined step(s)", stringBuilder.toString(),
                                "The scenario has pending or undefined step(s)");
                        Junit.appendChild(exceptionJunit);
                    } else {
                        element.setAttribute(STATUS, "SKIP");
                        Element skippedElementJunit = docJunit.createElement("skipped");
                        Junit.appendChild(skippedElementJunit);
                        Element systemOut = systemOutPrintJunit(docJunit, stringBuilder.toString());
                        Junit.appendChild(systemOut);
                    }

                } else {
                    element.setAttribute(STATUS, "PASS");
                    Element exception = createException(doc, "NonRealException", stringBuilder.toString(), " ");
                    element.appendChild(exception);
                    Element systemOut = systemOutPrintJunit(docJunit, stringBuilder.toString());
                    Junit.appendChild(systemOut);
                }
            }
        }

        private double calculateTotalDurationString() {
            double totalDurationNanos = 0;
            for (Result r : results) {
                totalDurationNanos += r.getDuration() == null ? 0 : r.getDuration();
            }
            for (Result r : hooks) {
                totalDurationNanos += r.getDuration() == null ? 0 : r.getDuration();
            }
            return totalDurationNanos / DURATION_STRING;
        }

        public void addStepAndResultListing(StringBuilder sb, List<Step> mergedsteps) {

            for (int i = 0; i < mergedsteps.size(); i++) {
                String resultStatus = "not executed";
                String resultStatusWarn = "*";
                if (i < results.size()) {
                    resultStatus = results.get(i).getStatus();
                    resultStatusWarn = ((results.get(i).getError() != null)
                            && (results.get(i).getStatus().equals("passed"))) ? "(W)" : "";
                }
                sb.append(mergedsteps.get(i).getKeyword());
                sb.append(mergedsteps.get(i).getName());
                int len = 0;
                len = mergedsteps.get(i).getKeyword().length() + mergedsteps.get(i).getName().length();
                if (mergedsteps.get(i).getRows() != null) {
                    for (DataTableRow row : mergedsteps.get(i).getRows()) {
                        StringBuilder strrowBuilder = new StringBuilder();
                        strrowBuilder.append("| ");
                        for (String cell : row.getCells()) {
                            strrowBuilder.append(cell).append(" | ");
                        }
                        String strrow = strrowBuilder.toString();
                        len = strrow.length() + DEFAULT_LENGTH;
                        sb.append("\n           ");
                        sb.append(strrow);
                    }
                }
                for (int j = 0; j + len < DEFAULT_MAX_LENGTH; j++) {
                    sb.append(".");
                }

                sb.append(resultStatus);
                sb.append(resultStatusWarn);
                sb.append("\n");
            }
            String cap = "";
            if (!("".equals(cap = hasCapture(featureName, scenario.getName())))) {
                sb.append("evidence @ " + System.getProperty("BUILD_URL", "") + "/artifact/testsAT/"
                        + cap.replaceAll("", ""));
            }
        }

        private String hasCapture(String feat, String scen) {
            String testSuffix = System.getProperty("TESTSUFFIX");
            File dir;
            if (testSuffix != null) {
                dir = new File("./target/executions/" + testSuffix + "/");
            } else {
                dir = new File("./target/executions/");
            }
            final String[] imgext = { "png" };
            Collection<File> files = FileUtils.listFiles(dir, imgext, true);

            for (File file : files) {
                if (file.getPath()
                        .contains(featureName.replaceAll(" ", "_") + "." + scenario.getName().replaceAll(" ", "_"))
                        && file.getName().contains("assert")) {
                    return file.toString();
                }
            }
            return "";
        }

        private Element createException(Document doc, String clazz, String message, String stacktrace) {
            Element exceptionElement = doc.createElement("exception");
            exceptionElement.setAttribute("class", clazz);

            if (message != null) {
                Element messageElement = doc.createElement("message");
                messageElement.appendChild(doc.createCDATASection("\r\n<pre>\r\n" + message + "\r\n</pre>\r\n"));
                exceptionElement.appendChild(messageElement);
            }

            Element stacktraceElement = doc.createElement("full-stacktrace");
            stacktraceElement.appendChild(doc.createCDATASection(stacktrace));
            exceptionElement.appendChild(stacktraceElement);

            return exceptionElement;
        }

        private Element createExceptionJunit(Document doc, String clazz, String message, String stacktrace) {
            Element exceptionElement = doc.createElement("failure");
            if (message != null) {
                exceptionElement.setAttribute("message", "\r\n" + message + "\r\n");
            }
            exceptionElement.appendChild(doc.createCDATASection(stacktrace));
            return exceptionElement;
        }

        private Element systemOutPrintJunit(Document doc, String message) {
            Element systemOut = doc.createElement("system-out");
            systemOut.appendChild(doc.createCDATASection("\r\n" + message + "\r\n"));
            return systemOut;
        }
    }
}