1e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson/*
2e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson * Copyright (c) 2007 Mockito contributors
3e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson * This program is made available under the terms of the MIT License.
4e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson */
5e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
6e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonpackage org.mockito;
7e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
8e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonimport org.mockito.configuration.AnnotationEngine;
9e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonimport org.mockito.configuration.DefaultMockitoConfiguration;
10e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonimport org.mockito.exceptions.Reporter;
11e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonimport org.mockito.exceptions.base.MockitoException;
12e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonimport org.mockito.internal.configuration.GlobalConfiguration;
13e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonimport org.mockito.internal.util.reflection.FieldSetter;
14e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonimport org.mockito.runners.MockitoJUnitRunner;
15e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
16e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonimport java.lang.annotation.Annotation;
17e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonimport java.lang.annotation.Retention;
18e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonimport java.lang.annotation.RetentionPolicy;
19e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonimport java.lang.annotation.Target;
20e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonimport java.lang.reflect.Field;
21e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
22e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonimport static java.lang.annotation.ElementType.FIELD;
23e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
24e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson/**
25e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson * MockitoAnnotations.initMocks(this); initializes fields annotated with Mockito annotations.
26e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson * <p>
27e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson * <ul>
28e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson * <li>Allows shorthand creation of objects required for testing.</li>
29e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson * <li>Minimizes repetitive mock creation code.</li>
30e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson * <li>Makes the test class more readable.</li>
31e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson * <li>Makes the verification error easier to read because <b>field name</b> is used to identify the mock.</li>
32e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson * </ul>
33e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson *
34e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson * <pre class="code"><code class="java">
35e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson *   public class ArticleManagerTest extends SampleBaseTestCase {
36e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson *
37e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson *       &#064;Mock private ArticleCalculator calculator;
38e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson *       &#064;Mock private ArticleDatabase database;
39e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson *       &#064;Mock private UserProvider userProvider;
40e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson *
41e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson *       private ArticleManager manager;
42e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson *
43e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson *       &#064;Before public void setup() {
44e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson *           manager = new ArticleManager(userProvider, database, calculator);
45e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson *       }
46e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson *   }
47e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson *
48e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson *   public class SampleBaseTestCase {
49e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson *
50e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson *       &#064;Before public void initMocks() {
51e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson *           MockitoAnnotations.initMocks(this);
52e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson *       }
53e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson *   }
54e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson * </code></pre>
55e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson * <p>
56e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson * Read also about other annotations &#064;{@link Spy}, &#064;{@link Captor}, &#064;{@link InjectMocks}
57e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson * <p>
58e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson * <b><code>MockitoAnnotations.initMocks(this)</code></b> method has to called to initialize annotated fields.
59e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson * <p>
60e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson * In above example, <code>initMocks()</code> is called in &#064;Before (JUnit4) method of test's base class.
61e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson * For JUnit3 <code>initMocks()</code> can go to <code>setup()</code> method of a base class.
62e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson * You can also put initMocks() in your JUnit runner (&#064;RunWith) or use built-in runner: {@link MockitoJUnitRunner}
63e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson */
64e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonpublic class MockitoAnnotations {
65e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
66e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson    /**
67e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson     * Use top-level {@link org.mockito.Mock} annotation instead
68e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson     * <p>
69e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson     * When &#064;Mock annotation was implemented as an inner class then users experienced problems with autocomplete features in IDEs.
70e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson     * Hence &#064;Mock was made a top-level class.
71e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson     * <p>
72e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson     * How to fix deprecation warnings?
73e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson     * Typically, you can just <b>search:</b> import org.mockito.MockitoAnnotations.Mock; <b>and replace with:</b> import org.mockito.Mock;
74e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson     * <p>
75e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson     * If you're an existing user then sorry for making your code littered with deprecation warnings.
76e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson     * This change was required to make Mockito better.
77e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson     */
78e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson    @Target( { FIELD })
79e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson    @Retention(RetentionPolicy.RUNTIME)
80e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson    @Deprecated
81e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson    public @interface Mock {}
82e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
83e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson    /**
84e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson     * Initializes objects annotated with Mockito annotations for given testClass:
85e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson     *  &#064;{@link org.mockito.Mock}, &#064;{@link Spy}, &#064;{@link Captor}, &#064;{@link InjectMocks}
86e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson     * <p>
87e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson     * See examples in javadoc for {@link MockitoAnnotations} class.
88e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson     */
89e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson    public static void initMocks(Object testClass) {
90e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        if (testClass == null) {
91e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson            throw new MockitoException("testClass cannot be null. For info how to use @Mock annotations see examples in javadoc for MockitoAnnotations class");
92e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        }
93e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
94e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        AnnotationEngine annotationEngine = new GlobalConfiguration().getAnnotationEngine();
95e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        Class<?> clazz = testClass.getClass();
96e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
97e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        //below can be removed later, when we get read rid of deprecated stuff
98e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        if (annotationEngine.getClass() != new DefaultMockitoConfiguration().getAnnotationEngine().getClass()) {
99e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson            //this means user has his own annotation engine and we have to respect that.
100e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson            //we will do annotation processing the old way so that we are backwards compatible
101e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson            while (clazz != Object.class) {
102e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson                scanDeprecatedWay(annotationEngine, testClass, clazz);
103e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson                clazz = clazz.getSuperclass();
104e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson            }
105e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        }
106e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
107e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        //anyway act 'the new' way
108e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        annotationEngine.process(testClass.getClass(), testClass);
109e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson    }
110e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
111e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson    static void scanDeprecatedWay(AnnotationEngine annotationEngine, Object testClass, Class<?> clazz) {
112e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        Field[] fields = clazz.getDeclaredFields();
113e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
114e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        for (Field field : fields) {
115e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson            processAnnotationDeprecatedWay(annotationEngine, testClass, field);
116e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        }
117e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson    }
118e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
119e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson    @SuppressWarnings("deprecation")
120e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson    static void processAnnotationDeprecatedWay(AnnotationEngine annotationEngine, Object testClass, Field field) {
121e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        boolean alreadyAssigned = false;
122e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        for(Annotation annotation : field.getAnnotations()) {
123e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson            Object mock = annotationEngine.createMockFor(annotation, field);
124e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson            if (mock != null) {
125e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson                throwIfAlreadyAssigned(field, alreadyAssigned);
126e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson                alreadyAssigned = true;
127e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson                try {
128e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson                    new FieldSetter(testClass, field).set(mock);
129e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson                } catch (Exception e) {
130e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson                    throw new MockitoException("Problems setting field " + field.getName() + " annotated with "
131e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson                            + annotation, e);
132e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson                }
133e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson            }
134e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        }
135e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson    }
136e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
137e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson    static void throwIfAlreadyAssigned(Field field, boolean alreadyAssigned) {
138e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        if (alreadyAssigned) {
139e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson            new Reporter().moreThanOneAnnotationNotAllowed(field.getName());
140e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        }
141e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson    }
142e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson}
143