1 package org.mockitoutil;
2 
3 import org.junit.runner.Result;
4 import org.junit.runner.notification.Failure;
5 
6 import java.util.List;
7 
8 import static org.junit.Assert.assertEquals;
9 import static org.mockito.internal.util.collections.Iterables.firstOf;
10 import static org.mockitoutil.TestBase.filterLineNo;
11 
12 /**
13  * Assertion utility for cleaner & easier to debug tests that inspect on JUnit's Result object
14  */
15 public class JUnitResultAssert {
16     private Result result;
17 
JUnitResultAssert(Result result)18     private JUnitResultAssert(Result result) {
19         this.result = result;
20     }
21 
isSuccessful()22     public void isSuccessful() {
23         if (result.wasSuccessful()) {
24             return;
25         }
26 
27         throw new AssertionError(formatFailures(result.getFailures()));
28     }
29 
30     /**
31      * @param expectedFailureCount - expected number of failures
32      * @param expectedException - the exception of each failure
33      */
fails(int expectedFailureCount, Class expectedException)34     public JUnitResultAssert fails(int expectedFailureCount, Class expectedException) {
35         fails(expectedFailureCount);
36         for (Failure f : result.getFailures()) {
37             if (!expectedException.isInstance(f.getException())) {
38                 throw new AssertionError("Incorrect failure type, expected: " + expectedException + ", actual: " + f.getException().getClass().getSimpleName() + "\n" +
39                         formatFailures(result.getFailures()));
40             }
41         }
42         return this;
43     }
44 
45     /**
46      * @param expectedFailureCount - exact number of expected failures
47      */
fails(int expectedFailureCount)48     public JUnitResultAssert fails(int expectedFailureCount) {
49         if (result.getFailures().size() != expectedFailureCount) {
50             throw new AssertionError("Wrong number of failures, expected: " + expectedFailureCount + ", actual: " + result.getFailures().size() + "\n" +
51                     formatFailures(result.getFailures()));
52         }
53         return this;
54     }
55 
56     /**
57      * @param expectedExceptions - failures must match the supplied sequence in order,
58      *                           if supplied input is empty, this method is a no-op
59      */
failsExactly(Class .... expectedExceptions)60     public JUnitResultAssert failsExactly(Class ... expectedExceptions) {
61         fails(expectedExceptions.length);
62         int i = 0;
63         for (Failure f : result.getFailures()) {
64             if (!expectedExceptions[i].isInstance(f.getException())) {
65                 throw new AssertionError("Actual failure #" + (i+1)
66                         + " should be of type: " + expectedExceptions[i].getSimpleName()
67                         + " but is of type: " + f.getException().getClass().getSimpleName()
68                         + "\n" + formatFailures(result.getFailures()));
69             }
70             i++;
71         }
72         return this;
73     }
74 
75     /**
76      * Expects single failure with specific exception and exception message.
77      * Automatically filters line numbers from exception messages.
78      */
fails(Class expectedException, String exceptionMessage)79     public JUnitResultAssert fails(Class expectedException, String exceptionMessage) {
80         fails(1, expectedException);
81         Failure f = firstOf(result.getFailures());
82         assertEquals(filterLineNo(exceptionMessage), filterLineNo(f.getException().getMessage()));
83         return this;
84     }
85 
86     /**
87      * Expects failure of given test method with given exception
88      */
fails(String methodName, Class expectedException)89     public JUnitResultAssert fails(String methodName, Class expectedException) {
90         for (Failure f : result.getFailures()) {
91             if (methodName.equals(f.getDescription().getMethodName()) && expectedException.isInstance(f.getException())) {
92                 return this;
93             }
94         }
95         throw new AssertionError("Method '" + methodName + "' did not fail with: " + expectedException.getSimpleName()
96                 + "\n" + formatFailures(result.getFailures()));
97     }
98 
99     /**
100      * Expects given amount of failures, with given exception triggered by given test method
101      */
fails(int expectedFailureCount, String methodName, Class expectedException)102     public JUnitResultAssert fails(int expectedFailureCount, String methodName, Class expectedException) {
103         return fails(expectedFailureCount, expectedException)
104                 .fails(methodName, expectedException);
105     }
106 
succeeds(int successCount)107     public JUnitResultAssert succeeds(int successCount) {
108         int i = result.getRunCount() - result.getFailureCount();
109         if (i != successCount) {
110             throw new AssertionError("Expected " + successCount + " passes but " + i + "/" + result.getRunCount() + " passed." +
111                     "\n" + formatFailures(result.getFailures()));
112         }
113         return this;
114     }
115 
formatFailures(List<Failure> failures)116     private static String formatFailures(List<Failure> failures) {
117         if (failures.isEmpty()) {
118             return "<no failures>";
119         }
120         StringBuilder sb = new StringBuilder("There were " + failures.size() + " test failures:\n");
121         int count = 0;
122         for (Failure f : failures) {
123             sb.append("  <-----> ").append(++count).append(". ").append(f.getTrace()).append("\n");
124         }
125 
126         return sb.toString();
127     }
128 
129     /**
130      * Clean assertions for JUnit's result object
131      */
assertThat(Result result)132     public static JUnitResultAssert assertThat(Result result) {
133         return new JUnitResultAssert(result);
134     }
135 }
136