VerboseReporter.java revision a7726191c419ea3086e36cf69207117c5a616e63
1/*
2 * To change this template, choose Tools | Templates
3 * and open the template in the editor.
4 */
5package org.testng.reporters;
6
7import java.lang.reflect.Method;
8import java.util.List;
9import org.testng.ITestContext;
10import org.testng.ITestNGMethod;
11import org.testng.ITestResult;
12import org.testng.TestListenerAdapter;
13import org.testng.internal.Utils;
14
15/**
16 *
17 * @author Lukas Jungmann
18 */
19//topic for discussion with Cedric
20//would be better to merge this class and org.testng.reporters.TextReporter
21//or keep this as separate listener?
22//main diferences are:
23// - format of the message being logged
24// - message is logged immediately instead of in onFinish event
25// - all messages have specific prefix
26public class VerboseReporter extends TestListenerAdapter {
27
28    public static final String LISTENER_PREFIX = "[VerboseTestNG] ";
29    private String testName;
30    private final String prefix;
31
32    public VerboseReporter() {
33        this(LISTENER_PREFIX);
34    }
35
36    public VerboseReporter(String prefix) {
37       this.prefix = prefix;
38    }
39
40    //see https://github.com/cbeust/testng/issues/124
41    private ITestResult r = null;
42
43    @Override
44    public void beforeConfiguration(ITestResult tr) {
45        if (tr.equals(r)) {
46            r = null;
47            System.out.println("BUG");
48            return;
49        }
50        r = tr;
51        super.beforeConfiguration(tr);
52        logResult("INVOKING CONFIGURATION", detailedMethodName(tr.getMethod(), true));
53    }
54
55    @Override
56    public void onConfigurationFailure(ITestResult tr) {
57        if (tr.equals(r)) {
58            r = null;
59            return;
60        }
61        r = tr;
62        super.onConfigurationFailure(tr);
63        Throwable ex = tr.getThrowable();
64        String stackTrace = "";
65        if (ex != null) {
66            stackTrace = Utils.stackTrace(ex, false)[0];
67        }
68        long duration = tr.getEndMillis() - tr.getStartMillis();
69        logResult("FAILED CONFIGURATION", detailedMethodName(tr.getMethod(), true), tr.getMethod().getDescription(), stackTrace, tr.getParameters(), tr.getMethod().getMethod().getParameterTypes(), duration);
70    }
71
72    @Override
73    public void onConfigurationSkip(ITestResult tr) {
74        if (tr.equals(r)) {
75            r = null;
76            System.out.println("BUG");
77            return;
78        }
79        r = tr;
80        super.onConfigurationSkip(tr);
81        long duration = tr.getEndMillis() - tr.getStartMillis();
82        logResult("SKIPPED CONFIGURATION", detailedMethodName(tr.getMethod(), true), tr.getMethod().getDescription(), null, tr.getParameters(), tr.getMethod().getMethod().getParameterTypes(), duration);
83    }
84
85    @Override
86    public void onConfigurationSuccess(ITestResult tr) {
87        if (tr.equals(r)) {
88            r = null;
89            return;
90        }
91        r = tr;
92        super.onConfigurationSuccess(tr);
93        long duration = tr.getEndMillis() - tr.getStartMillis();
94        logResult("PASSED CONFIGURATION", detailedMethodName(tr.getMethod(), true), tr.getMethod().getDescription(), null, tr.getParameters(), tr.getMethod().getMethod().getParameterTypes(), duration);
95    }
96
97    @Override
98    public void onTestFailure(ITestResult tr) {
99        super.onTestFailure(tr);
100        Throwable ex = tr.getThrowable();
101        String stackTrace = "";
102        if (ex != null) {
103            stackTrace = Utils.stackTrace(ex, false)[0];
104        }
105        logResult("FAILED", tr, stackTrace);
106    }
107
108    @Override
109    public void onTestFailedButWithinSuccessPercentage(ITestResult tr) {
110        super.onTestFailedButWithinSuccessPercentage(tr);
111        logResult("PASSED with failures", tr, null);
112    }
113
114    @Override
115    public void onTestSkipped(ITestResult tr) {
116        super.onTestSkipped(tr);
117        Throwable throwable = tr.getThrowable();
118        logResult("SKIPPED", tr, throwable != null ? Utils.stackTrace(throwable, false)[0] : null);
119    }
120
121    @Override
122    public void onTestSuccess(ITestResult tr) {
123        super.onTestSuccess(tr);
124        logResult("PASSED", tr, null);
125    }
126
127    @Override
128    public void onStart(ITestContext ctx) {
129        testName = ctx.getName();//ctx.getSuite().getXmlSuite().getFileName();
130        logResult("RUNNING", "Suite: \"" + testName + "\" containing \"" + ctx.getAllTestMethods().length + "\" Tests (config: " + ctx.getSuite().getXmlSuite().getFileName() + ")");
131
132    }
133
134    @Override
135    public void onFinish(ITestContext context) {
136        logResults();
137        testName = null;
138    }
139
140    @Override
141    public void onTestStart(ITestResult tr) {
142        logResult("INVOKING", detailedMethodName(tr.getMethod(), true));
143    }
144
145    private ITestNGMethod[] resultsToMethods(List<ITestResult> results) {
146        ITestNGMethod[] result = new ITestNGMethod[results.size()];
147        int i = 0;
148        for (ITestResult tr : results) {
149            result[i++] = tr.getMethod();
150        }
151        return result;
152    }
153
154    private void logResults() {
155        //
156        // Log test summary
157        //
158        ITestNGMethod[] ft = resultsToMethods(getFailedTests());
159        StringBuffer logBuf = new StringBuffer("\n===============================================\n");
160        logBuf.append("    ").append(getName()).append("\n");
161        logBuf.append("    Tests run: ").append(Utils.calculateInvokedMethodCount(getAllTestMethods())).append(", Failures: ").append(Utils.calculateInvokedMethodCount(ft)).append(", Skips: ").append(Utils.calculateInvokedMethodCount(resultsToMethods(getSkippedTests())));
162        int confFailures = getConfigurationFailures().size();
163        int confSkips = getConfigurationSkips().size();
164        if (confFailures > 0 || confSkips > 0) {
165            logBuf.append("\n").append("    Configuration Failures: ").append(confFailures).append(", Skips: ").append(confSkips);
166        }
167        logBuf.append("\n===============================================");
168        logResult("", logBuf.toString());
169    }
170
171    private String getName() {
172        return testName;
173    }
174
175    private void logResult(String status, ITestResult tr, String stackTrace) {
176        long duration = tr.getEndMillis() - tr.getStartMillis();
177        logResult(status, detailedMethodName(tr.getMethod(), true), tr.getMethod().getDescription(), stackTrace, tr.getParameters(), tr.getMethod().getMethod().getParameterTypes(), duration);
178    }
179
180    private void logResult(String status, String message) {
181        StringBuffer buf = new StringBuffer();
182        if (Utils.isStringNotBlank(status)) {
183            buf.append(status).append(": ");
184        }
185        buf.append(message);
186//        System.out.println("LOG: " + buf.toString());
187        //prefix all output lines
188        System.out.println(buf.toString().replaceAll("(?m)^", prefix));
189    }
190
191    private void logResult(String status, String name, String description, String stackTrace, Object[] params, Class[] paramTypes, long duration) {
192        StringBuffer msg = new StringBuffer(name);
193        if (null != params && params.length > 0) {
194            msg.append("(value(s): ");
195            // The error might be a data provider parameter mismatch, so make
196            // a special case here
197            if (params.length != paramTypes.length) {
198                msg.append(name + ": Wrong number of arguments were passed by " + "the Data Provider: found " + params.length + " but " + "expected " + paramTypes.length + ")");
199            } else {
200                for (int i = 0; i < params.length; i++) {
201                    if (i > 0) {
202                        msg.append(", ");
203                    }
204                    msg.append(Utils.toString(params[i], paramTypes[i]));
205                }
206                msg.append(")");
207            }
208        }
209        msg.append(" finished in ");
210        msg.append(duration);
211        msg.append(" ms");
212        if (!Utils.isStringEmpty(description)) {
213            msg.append("\n");
214            for (int i = 0; i < status.length() + 2; i++) {
215                msg.append(" ");
216            }
217            msg.append(description);
218        }
219        if (!Utils.isStringEmpty(stackTrace)) {
220            msg.append("\n").append(stackTrace.substring(0, stackTrace.lastIndexOf(System.getProperty("line.separator"))));
221        }
222        logResult(status, msg.toString());
223    }
224
225    @Deprecated
226    //perhaps should rather to adopt the original method
227    private String detailedMethodName(ITestNGMethod method, boolean fqn) {
228        Method m = method.getMethod();
229        StringBuffer buf = new StringBuffer();
230        buf.append("\"");
231        if (getName() != null) {
232            buf.append(getName());
233        } else {
234            buf.append("UNKNOWN");
235        }
236        buf.append("\"");
237        buf.append(" - ");
238        if (method.isBeforeSuiteConfiguration()) {
239            buf.append("@BeforeSuite ");
240        } else if (method.isBeforeTestConfiguration()) {
241            buf.append("@BeforeTest ");
242        } else if (method.isBeforeClassConfiguration()) {
243            buf.append("@BeforeClass ");
244        } else if (method.isBeforeGroupsConfiguration()) {
245            buf.append("@BeforeGroups ");
246        } else if (method.isBeforeMethodConfiguration()) {
247            buf.append("@BeforeMethod ");
248        } else if (method.isAfterMethodConfiguration()) {
249            buf.append("@AfterMethod ");
250        } else if (method.isAfterGroupsConfiguration()) {
251            buf.append("@AfterGroups ");
252        } else if (method.isAfterClassConfiguration()) {
253            buf.append("@AfterClass ");
254        } else if (method.isAfterTestConfiguration()) {
255            buf.append("@AfterTest ");
256        } else if (method.isAfterSuiteConfiguration()) {
257            buf.append("@AfterSuite ");
258        }
259        buf.append(m.getDeclaringClass().getName());
260        buf.append(".");
261        buf.append(m.getName());
262        buf.append("(");
263        int i = 0;
264        for (Class<?> p : m.getParameterTypes()) {
265            if (i++ > 0) {
266                buf.append(", ");
267            }
268            buf.append(p.getName());
269        }
270        buf.append(")");
271        return buf.toString();//buf.append(fqn ? method.toString() : method.getMethodName()).toString();
272    }
273
274    @Override
275    public String toString() {
276        return "VerboseReporter{" + "testName=" + testName + ", r=" + r + '}';
277    }
278
279}
280