View Javadoc
1   package org.apache.maven.surefire.common.junit4;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.surefire.report.ReportEntry;
23  import org.apache.maven.surefire.report.RunListener;
24  import org.apache.maven.surefire.report.SimpleReportEntry;
25  import org.apache.maven.surefire.report.StackTraceWriter;
26  import org.apache.maven.surefire.testset.TestSetFailedException;
27  import org.apache.maven.surefire.util.internal.ClassMethod;
28  import org.junit.runner.Description;
29  import org.junit.runner.Result;
30  import org.junit.runner.notification.Failure;
31  
32  import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.isFailureInsideJUnitItself;
33  import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.toClassMethod;
34  import static org.apache.maven.surefire.common.junit4.JUnit4Reflector.getAnnotatedIgnoreValue;
35  import static org.apache.maven.surefire.report.SimpleReportEntry.assumption;
36  import static org.apache.maven.surefire.report.SimpleReportEntry.ignored;
37  import static org.apache.maven.surefire.report.SimpleReportEntry.withException;
38  
39  /**
40   * RunListener for JUnit4, delegates to our own RunListener
41   *
42   */
43  public class JUnit4RunListener
44      extends org.junit.runner.notification.RunListener
45  {
46      protected final RunListener reporter;
47  
48      /**
49       * This flag is set after a failure has occurred so that a {@link RunListener#testSucceeded} event is not fired.
50       * This is necessary because JUnit4 always fires a
51       * {@link org.junit.runner.notification.RunListener#testRunFinished(Result)}
52       * event-- even if there was a failure.
53       */
54      private final ThreadLocal<Boolean> failureFlag = new InheritableThreadLocal<>();
55  
56      /**
57       * Constructor.
58       *
59       * @param reporter the reporter to log testing events to
60       */
61      public JUnit4RunListener( RunListener reporter )
62      {
63          this.reporter = reporter;
64      }
65  
66      // Testrun methods are not invoked when using the runner
67  
68      /**
69       * Called when a specific test has been skipped (for whatever reason).
70       *
71       * @see org.junit.runner.notification.RunListener#testIgnored(org.junit.runner.Description)
72       */
73      @Override
74      public void testIgnored( Description description )
75          throws Exception
76      {
77          String reason = getAnnotatedIgnoreValue( description );
78          ClassMethod classMethod = toClassMethod( description );
79          reporter.testSkipped( ignored( classMethod.getClazz(), null, classMethod.getMethod(), null, reason ) );
80      }
81  
82      /**
83       * Called when a specific test has started.
84       *
85       * @see org.junit.runner.notification.RunListener#testStarted(org.junit.runner.Description)
86       */
87      @Override
88      public void testStarted( Description description )
89          throws Exception
90      {
91          try
92          {
93              reporter.testStarting( createReportEntry( description ) );
94          }
95          finally
96          {
97              failureFlag.remove();
98          }
99      }
100 
101     /**
102      * Called when a specific test has failed.
103      *
104      * @see org.junit.runner.notification.RunListener#testFailure(org.junit.runner.notification.Failure)
105      */
106     @Override
107     @SuppressWarnings( { "ThrowableResultOfMethodCallIgnored" } )
108     public void testFailure( Failure failure )
109         throws Exception
110     {
111         try
112         {
113             StackTraceWriter stackTrace = createStackTraceWriter( failure );
114             ClassMethod classMethod = toClassMethod( failure.getDescription() );
115             ReportEntry report =
116                     withException( classMethod.getClazz(), null, classMethod.getMethod(), null, stackTrace );
117 
118             if ( failure.getException() instanceof AssertionError )
119             {
120                 reporter.testFailed( report );
121             }
122             else
123             {
124                 reporter.testError( report );
125             }
126         }
127         finally
128         {
129             failureFlag.set( true );
130         }
131     }
132 
133     public void testAssumptionFailure( Failure failure )
134     {
135         try
136         {
137             Description desc = failure.getDescription();
138             ClassMethod classMethod = toClassMethod( desc );
139             ReportEntry report = assumption( classMethod.getClazz(), null, classMethod.getMethod(), null,
140                     failure.getMessage() );
141             reporter.testAssumptionFailure( report );
142         }
143         finally
144         {
145             failureFlag.set( true );
146         }
147     }
148 
149     /**
150      * Called after a specific test has finished.
151      *
152      * @see org.junit.runner.notification.RunListener#testFinished(org.junit.runner.Description)
153      */
154     @Override
155     public void testFinished( Description description )
156         throws Exception
157     {
158         Boolean failure = failureFlag.get();
159         if ( failure == null )
160         {
161             reporter.testSucceeded( createReportEntry( description ) );
162         }
163     }
164 
165     /**
166      * Delegates to {@link RunListener#testExecutionSkippedByUser()}.
167      */
168     public void testExecutionSkippedByUser()
169     {
170         reporter.testExecutionSkippedByUser();
171     }
172 
173     protected StackTraceWriter createStackTraceWriter( Failure failure )
174     {
175         return new JUnit4StackTraceWriter( failure );
176     }
177 
178     protected SimpleReportEntry createReportEntry( Description description )
179     {
180         ClassMethod classMethod = toClassMethod( description );
181         return new SimpleReportEntry( classMethod.getClazz(), null, classMethod.getMethod(), null );
182     }
183 
184     public static void rethrowAnyTestMechanismFailures( Result run )
185         throws TestSetFailedException
186     {
187         for ( Failure failure : run.getFailures() )
188         {
189             if ( isFailureInsideJUnitItself( failure.getDescription() ) )
190             {
191                 throw new TestSetFailedException( failure.getTestHeader() + " :: " + failure.getMessage(),
192                                                         failure.getException() );
193             }
194         }
195     }
196 }