How to use method of org.easymock.internal.Injector class

Best Easymock code snippet using org.easymock.internal.Injector.

Run Easymock automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

copy
1/*
2 * Copyright 2001-2021 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.easymock.internal;
17
18import org.easymock.*;
19
20import java.lang.reflect.Constructor;
21import java.lang.reflect.Field;
22import java.lang.reflect.Modifier;
23import java.util.ArrayList;
24import java.util.List;
25
26import static java.util.Arrays.*;
27
28/**
29 * Performs creation of mocks and injection into test subjects in accordance with annotations present in the host object.
30 *
31 * @author Henri Tremblay
32 * @author Alistair Todd
33 * @since 3.3
34 */
35public class Injector {
36
37    /**
38     * Inject a mock to every fields annotated with {@link Mock} on the class passed
39     * in parameter. Then, inject these mocks to the fields of every class annotated with {@link TestSubject}.
40     * <p>
41     * The rules are
42     * <ul>
43     *     <li>Static and final fields are ignored</li>
44     *     <li>If two mocks have the same field name, return an error</li>
45     *     <li>If a mock has a field name and no matching field is found, return an error</li>
46     * </ul>
47     * Then, ignoring all fields and mocks matched by field name
48     * <ul>
49     *     <li>If a mock without field name can be assigned to a field, do it. The same mock can be assigned more than once</li>
50     *     <li>If no mock can be assigned to a field, skip the field silently</li>
51     *     <li>If the mock cannot be assigned to any field, skip the mock silently</li>
52     *     <li>If two mocks can be assigned to the same field, return an error</li>
53     * </ul>
54     * Fields are searched recursively on the superclasses
55     * <p>
56     * <b>Note:</b> If the parameter extends {@link EasyMockSupport}, the mocks will be created using it to allow
57     * {@code replayAll/verifyAll} to work afterwards
58     * @param host the object on which to inject mocks
59     * @since 3.2
60     */
61    public static void injectMocks(Object host) {
62
63        InjectionPlan injectionPlan = new InjectionPlan();
64
65        Class<?> hostClass = host.getClass();
66        while (hostClass != Object.class) {
67            createMocksForAnnotations(hostClass, host, injectionPlan);
68            hostClass = hostClass.getSuperclass();
69        }
70
71        for (Field f : injectionPlan.getTestSubjectFields()) {
72            f.setAccessible(true);
73            Object testSubject;
74            try {
75                testSubject = f.get(host);
76            } catch (IllegalAccessException e) {
77                // ///CLOVER:OFF
78                throw new AssertionError(e);
79                // ///CLOVER:ON
80            }
81            if (testSubject == null) {
82                // The attribute isn't initialized, try to call the default constructor
83                testSubject = instantiateTestSubject(f);
84                try {
85                    f.setAccessible(true);
86                    f.set(host, testSubject);
87                } catch (ReflectiveOperationException e) {
88                    throw new AssertionError("Failed to assign the created TestSubject to  " + f.getName(), e);
89                }
90            }
91            Class<?> testSubjectClass = testSubject.getClass();
92            while (testSubjectClass != Object.class) {
93                injectMocksOnClass(testSubjectClass, testSubject, injectionPlan);
94                testSubjectClass = testSubjectClass.getSuperclass();
95            }
96        }
97
98        // Check for unsatisfied qualified injections only after having scanned all TestSubjects and their superclasses
99        for (Injection injection : injectionPlan.getQualifiedInjections()) {
100            if (!injection.isMatched()) {
101                throw new AssertionError(
102                        String.format("Unsatisfied qualifier: '%s'", injection.getAnnotation().fieldName()));
103            }
104        }
105    }
106
107    static <T> T instantiateTestSubject(Field f) {
108        T testSubject;
109        @SuppressWarnings("unchecked")
110        Class<T> type = (Class<T>) f.getType();
111        if(type.isMemberClass() && !Modifier.isStatic(type.getModifiers())) {
112            throw new AssertionError("TestSubject is an inner class. You need to instantiate '" + f.getName() + "' manually");
113        }
114        Constructor<T> defaultConstructor;
115        try {
116            defaultConstructor = type.getDeclaredConstructor();
117        } catch (NoSuchMethodException e) {
118            throw new AssertionError("TestSubject is null and has no default constructor. You need to instantiate '" + f.getName() + "' manually");
119        }
120        defaultConstructor.setAccessible(true);
121        try {
122            testSubject = defaultConstructor.newInstance();
123        } catch (ReflectiveOperationException e) {
124            throw new AssertionError("TestSubject is null and default constructor fails on invocation. You need to instantiate '" + f.getName() + "' manually", e);
125        }
126        return testSubject;
127    }
128
129    /**
130     * Create the mocks and find the fields annotated with {@link TestSubject}
131     *
132     * @param hostClass class to search
133     * @param host object of the class
134     * @param injectionPlan output parameter where the created mocks and fields to inject are added
135     */
136    private static void createMocksForAnnotations(Class<?> hostClass, Object host,
137            InjectionPlan injectionPlan) {
138        Field[] fields = hostClass.getDeclaredFields();
139        for (Field f : fields) {
140            TestSubject ima = f.getAnnotation(TestSubject.class);
141            if (ima != null) {
142                injectionPlan.addTestSubjectField(f);
143                continue;
144            }
145            Mock annotation = f.getAnnotation(Mock.class);
146            if (annotation == null) {
147                continue;
148            }
149            Class<?> type = f.getType();
150            String name = annotation.name();
151            // Empty string means we are on the default value which we means no name (aka null) from the EasyMock point of view
152            name = (name.length() == 0 ? null : name);
153
154            MockType mockType = mockTypeFromAnnotation(annotation);
155            Object mock;
156            if (host instanceof EasyMockSupport) {
157                mock = ((EasyMockSupport) host).createMock(name, mockType, type);
158            }
159            else {
160                mock = EasyMock.createMock(name, mockType, type);
161            }
162            f.setAccessible(true);
163            try {
164                f.set(host, mock);
165            } catch (IllegalAccessException e) {
166                // ///CLOVER:OFF
167                throw new RuntimeException(e);
168                // ///CLOVER:ON
169            }
170
171            injectionPlan.addInjection(new Injection(mock, annotation));
172        }
173    }
174
175    private static MockType mockTypeFromAnnotation(Mock annotation) {
176        MockType valueMockType = annotation.value();
177        MockType mockType = annotation.type();
178        if(valueMockType != MockType.DEFAULT && mockType != MockType.DEFAULT) {
179            throw new AssertionError("@Mock.value() and @Mock.type() are aliases, you can't specify both at the same time");
180        }
181        if(valueMockType != MockType.DEFAULT) {
182            mockType = valueMockType;
183        }
184        return mockType;
185    }
186
187    /**
188     * Try to inject a mock to every fields in the class
189     *
190     * @param clazz class where the fields are taken
191     * @param obj object being a instance of clazz
192     * @param injectionPlan details of possible mocks for injection
193     */
194    private static void injectMocksOnClass(Class<?> clazz, Object obj,
195            InjectionPlan injectionPlan) {
196
197        List<Field> fields = injectByName(clazz, obj, injectionPlan.getQualifiedInjections());
198        injectByType(obj, fields, injectionPlan.getUnqualifiedInjections());
199    }
200
201    private static List<Field> injectByName(Class<?> clazz, Object obj,
202            List<Injection> qualifiedInjections) {
203
204        List<Field> fields = fieldsOf(clazz);
205
206        for (Injection injection : qualifiedInjections) {
207
208            Field f = getFieldByName(clazz, injection.getQualifier());
209            InjectionTarget target = injectionTargetWithField(f);
210            if (target == null) {
211                continue;
212            }
213
214            if (target.accepts(injection)) {
215                target.inject(obj, injection);
216                fields.remove(target.getTargetField());
217            }
218        }
219
220        return fields;
221    }
222
223    private static void injectByType(Object obj, List<Field> fields,
224            List<Injection> injections) {
225
226        for (Field f : fields) {
227
228            InjectionTarget target = injectionTargetWithField(f);
229            if (target == null) {
230                continue;
231            }
232
233            Injection toAssign = findUniqueAssignable(injections, target);
234            if (toAssign == null) {
235                continue;
236            }
237
238            target.inject(obj, toAssign);
239        }
240    }
241
242    private static List<Field> fieldsOf(Class<?> clazz) {
243        return new ArrayList<>(asList(clazz.getDeclaredFields()));
244    }
245
246    private static Field getFieldByName(Class<?> clazz, String fieldName) {
247        try {
248            return clazz.getDeclaredField(fieldName);
249        } catch (NoSuchFieldException | SecurityException e) {
250            return null;
251        }
252    }
253
254    private static InjectionTarget injectionTargetWithField(Field f) {
255        if (shouldNotAssignTo(f)) {
256            return null;
257        }
258        return new InjectionTarget(f);
259    }
260
261    private static boolean shouldNotAssignTo(Field f) {
262        // Skip final or static fields
263        return f == null || (f.getModifiers() & (Modifier.STATIC + Modifier.FINAL)) != 0;
264    }
265
266    private static Injection findUniqueAssignable(List<Injection> injections,
267            InjectionTarget target) {
268        Injection toAssign = null;
269        for (Injection injection : injections) {
270            if (target.accepts(injection)) {
271                if (toAssign != null) {
272                    throw new AssertionError(
273                            String.format("At least two mocks can be assigned to '%s': %s and %s",
274                                    target.getTargetField(), toAssign.getMock(), injection.getMock()));
275                }
276                toAssign = injection;
277            }
278        }
279        return toAssign;
280    }
281
282}
283
Full Screen

Accelerate Your Automation Test Cycles With LambdaTest

Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.

Try LambdaTest

Trigger code on LambdaTest Cloud Grid

Execute automation tests with on a cloud-based Grid of 3000+ real browsers and operating systems for both web and mobile applications.

Test now for Free
LambdaTestX

We use cookies to give you the best experience. Cookies help to provide a more personalized experience and relevant advertising for you, and web analytics for us. Learn More in our Cookies policy, Privacy & Terms of service

Allow Cookie
Sarah

I hope you find the best code examples for your project.

If you want to accelerate automated browser testing, try LambdaTest. Your first 100 automation testing minutes are FREE.

Sarah Elson (Product & Growth Lead)