44 */
55package org .mockito .testng ;
66
7+ import java .lang .annotation .Annotation ;
8+ import java .util .Arrays ;
79import java .util .Map ;
810import java .util .Optional ;
911import java .util .WeakHashMap ;
12+ import java .util .stream .Stream ;
1013
1114import org .mockito .Mockito ;
1215import org .mockito .MockitoSession ;
1316import org .mockito .quality .Strictness ;
1417import org .testng .IInvokedMethod ;
1518import org .testng .IInvokedMethodListener ;
16- import org .testng .ITestNGListener ;
19+ import org .testng .ITestNGMethod ;
1720import org .testng .ITestResult ;
1821import org .testng .annotations .Listeners ;
1922
5558 * </code></pre>
5659 *
5760 * <p>
61+ * By default {@link MockitoSession} is started with {@link Strictness#STRICT_STUBS}.
62+ * You can change this behavior by adding {@link MockitoSettings} to your test class.
63+ * </p>
64+ *
65+ * <pre class="code"><code class="java">
66+ * <b>@Listeners(MockitoTestNGListener.class)</b>
67+ * <b>@MockitoSettings(strictness = Strictness.WARN)</b>
68+ * public class ExampleTest {
69+ * ...
70+ * }
71+ * </code></pre>
72+ *
73+ * <p>
5874 * <code>MockitoTestNGListener</code> not working with parallel tests,
5975 * more information https://github.com/mockito/mockito-testng/issues/20
6076 * </p>
@@ -65,49 +81,65 @@ public class MockitoTestNGListener implements IInvokedMethodListener {
6581
6682 @ Override
6783 public void beforeInvocation (IInvokedMethod method , ITestResult testResult ) {
68- if (hasMockitoTestNGListenerInTestHierarchy (testResult )) {
69- sessions .computeIfAbsent (testResult .getInstance (), testInstance ->
70- Mockito .mockitoSession ()
71- .initMocks (testInstance )
72- .strictness (Strictness .STRICT_STUBS )
73- .startMocking ()
84+ if (shouldBeRunBeforeInvocation (method , testResult )) {
85+ sessions .computeIfAbsent (testResult .getInstance (), testInstance -> {
86+
87+ Strictness strictness = findAnnotation (testResult , MockitoSettings .class )
88+ .map (MockitoSettings ::strictness ).orElse (Strictness .STRICT_STUBS );
89+
90+ return Mockito .mockitoSession ()
91+ .initMocks (testInstance )
92+ .strictness (strictness )
93+ .startMocking ();
94+ }
7495 );
7596 }
7697 }
7798
7899 @ Override
79100 public void afterInvocation (IInvokedMethod method , ITestResult testResult ) {
80- if (hasMockitoTestNGListenerInTestHierarchy ( testResult ) && method . isTestMethod ( )) {
101+ if (shouldBeRunAfterInvocation ( method , testResult )) {
81102 Optional .ofNullable (sessions .remove (testResult .getInstance ()))
82103 .ifPresent (mockitoSession -> mockitoSession .finishMocking (testResult .getThrowable ()));
83104 }
84105 }
85106
86- protected boolean hasMockitoTestNGListenerInTestHierarchy (ITestResult testResult ) {
87- for (Class <?> clazz = testResult .getTestClass ().getRealClass (); clazz != Object .class ; clazz = clazz .getSuperclass ()) {
88- if (hasMockitoTestNGListener (clazz )) {
89- return true ;
90- }
91- }
92- return false ;
107+ private boolean shouldBeRunBeforeInvocation (IInvokedMethod method , ITestResult testResult ) {
108+ return !isAfterConfigurationMethod (method ) && hasMockitoTestNGListener (testResult );
93109 }
94110
95- protected boolean hasMockitoTestNGListener (Class <?> clazz ) {
96- Listeners listeners = clazz .getAnnotation (Listeners .class );
97- if (listeners == null ) {
98- return false ;
99- }
111+ private boolean isAfterConfigurationMethod (IInvokedMethod method ) {
112+ ITestNGMethod testMethod = method .getTestMethod ();
113+ return testMethod .isAfterClassConfiguration ()
114+ || testMethod .isAfterMethodConfiguration ()
115+ || testMethod .isAfterGroupsConfiguration ()
116+ || testMethod .isAfterTestConfiguration ()
117+ || testMethod .isAfterSuiteConfiguration ();
118+ }
100119
101- for (Class <? extends ITestNGListener > listenerClass : listeners .value ()) {
102- if (listenerClass () == listenerClass ) {
103- return true ;
104- }
105- }
106- return false ;
120+ private boolean shouldBeRunAfterInvocation (IInvokedMethod method , ITestResult testResult ) {
121+ return method .isTestMethod () && hasMockitoTestNGListener (testResult );
107122 }
108123
109- protected Class <MockitoTestNGListener > listenerClass () {
110- return MockitoTestNGListener .class ;
124+ protected boolean hasMockitoTestNGListener (ITestResult testResult ) {
125+
126+ return findAnnotation (testResult , Listeners .class )
127+ .map (Listeners ::value )
128+ .map (Arrays ::stream )
129+ .orElseGet (Stream ::empty )
130+ .anyMatch (listener -> listener == MockitoTestNGListener .class );
111131 }
112132
133+ <A extends Annotation > Optional <A > findAnnotation (ITestResult testResult , Class <A > annotationClass ) {
134+
135+ for (Class <?> clazz = testResult .getTestClass ().getRealClass ();
136+ clazz != Object .class ; clazz = clazz .getSuperclass ()) {
137+ Optional <A > annotation = Optional .ofNullable (clazz .getAnnotation (annotationClass ));
138+ if (annotation .isPresent ()) {
139+ return annotation ;
140+ }
141+ }
142+
143+ return Optional .empty ();
144+ }
113145}
0 commit comments