kubek2k avatar kubek2k committed 40d00df Merge

Merge context-cache #16

Comments (0)

Files changed (4)

springockito-annotations/src/main/java/org/kubek2k/springockito/annotations/DesiredMockitoBeansFinder.java

 package org.kubek2k.springockito.annotations;
 
-import sun.reflect.annotation.AnnotationType;
-
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 class DesiredMockitoBeansFinder {
     public static class MockProperties<AnnotationType extends Annotation> {
-        private AnnotationType annotationValues;
+        private AnnotationType annotationInstance;
 
         private Class<?> mockClass;
+        private AnnotationClasspathRepresentationCreator<AnnotationType> annotationClasspathRepresentationCreator;
 
-        public MockProperties(AnnotationType annotationValues, Class<?> mockClass) {
-            this.annotationValues = annotationValues;
+        public MockProperties(AnnotationType annotationInstance, Class<?> mockClass, AnnotationClasspathRepresentationCreator<AnnotationType> annotationClasspathRepresentationCreator) {
+            this.annotationInstance = annotationInstance;
             this.mockClass = mockClass;
+            this.annotationClasspathRepresentationCreator = annotationClasspathRepresentationCreator;
         }
 
-        public AnnotationType getAnnotationValues() {
-            return annotationValues;
+        public AnnotationType getAnnotationInstance() {
+            return annotationInstance;
         }
 
         public Class<?> getMockClass() {
             return mockClass;
         }
+
+        public String getClasspathRepresentation() {
+            return mockClass + ":" + annotationClasspathRepresentationCreator.toClasspathRepresentation(annotationInstance);
+        }
+
+    }
+
+    private interface AnnotationClasspathRepresentationCreator<AnnotationType extends Annotation> {
+
+        public String toClasspathRepresentation(AnnotationType annotationType);
+
     }
 
     public Map<String, MockProperties<ReplaceWithMock>> findMockedBeans(Class<?> clazz) {
-        return findAnnotatedFieldsTypes(clazz.getDeclaredFields(), ReplaceWithMock.class);
+        return findAnnotatedFieldsTypes(clazz.getDeclaredFields(), ReplaceWithMock.class, new AnnotationClasspathRepresentationCreator<ReplaceWithMock>() {
+            public String toClasspathRepresentation(ReplaceWithMock replaceWithMock) {
+                String defaultAnswer = replaceWithMock.defaultAnswer() != null ? replaceWithMock.defaultAnswer().toString() : "";
+                String extraInterfaces = replaceWithMock.extraInterfaces() != null ? Arrays.toString(replaceWithMock.extraInterfaces()) : "";
+                return replaceWithMock.name() + "," + defaultAnswer + "," + extraInterfaces;
+            }
+        });
     }
 
     public Set<String> findSpiedBeans(Class<?> clazz) {
-        return findAnnotatedFieldsTypes(clazz.getDeclaredFields(), WrapWithSpy.class).keySet();
+        return findAnnotatedFieldsTypes(clazz.getDeclaredFields(), WrapWithSpy.class, new AnnotationClasspathRepresentationCreator<WrapWithSpy>() {
+            public String toClasspathRepresentation(WrapWithSpy wrapWithSpy) {
+                return "";
+            }
+        }).keySet();
     }
 
-    private <AnnotationType extends Annotation> Map<String, MockProperties<AnnotationType>> findAnnotatedFieldsTypes(Field[] fieldsToScan, Class<AnnotationType> annotationClass) {
-        Map<String, MockProperties<AnnotationType>> mockedBeans = new HashMap<String, MockProperties<AnnotationType>>();
+    private <AnnotationType extends Annotation> Map<String, MockProperties<AnnotationType>> findAnnotatedFieldsTypes(Field[] fieldsToScan, Class<AnnotationType> annotationClass, AnnotationClasspathRepresentationCreator<AnnotationType> annotationClasspathRepresentationCreator) {
+        Map<String, MockProperties<AnnotationType>> mockedBeans = new LinkedHashMap<String, MockProperties<AnnotationType>>();
         for (Field field : fieldsToScan) {
             Annotation replaceWithMockAnnotation = field.getAnnotation(annotationClass);
             if (replaceWithMockAnnotation != null) {
-                mockedBeans.put(field.getName(), new MockProperties<AnnotationType>((AnnotationType)field.getAnnotation(annotationClass), field.getType()));
+                mockedBeans.put(field.getName(), new MockProperties<AnnotationType>((AnnotationType)field.getAnnotation(annotationClass), field.getType(), annotationClasspathRepresentationCreator));
             }
         }
         return mockedBeans;
     }
+
 }

springockito-annotations/src/main/java/org/kubek2k/springockito/annotations/SpringockitoContextLoader.java

 package org.kubek2k.springockito.annotations;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
 import org.springframework.beans.factory.config.BeanDefinition;
 import org.springframework.context.support.GenericApplicationContext;
 import org.springframework.test.context.support.GenericXmlContextLoader;
 
+import java.util.*;
+
 public class SpringockitoContextLoader extends GenericXmlContextLoader {
 
+    /**
+     * Have to be sorted since we want a nice caching of customized application contexts
+     */
     private Map<String, DesiredMockitoBeansFinder.MockProperties<ReplaceWithMock>> mockedBeans
-            = new HashMap<String, DesiredMockitoBeansFinder.MockProperties<ReplaceWithMock>>();
-    private Set<String> spiedBeans;
+            = new TreeMap<String, DesiredMockitoBeansFinder.MockProperties<ReplaceWithMock>>();
+    private Set<String> spiedBeans = new TreeSet<String>();
 
     private DesiredMockitoBeansFinder mockedBeansFinder = new DesiredMockitoBeansFinder();
 
                                Map<String, DesiredMockitoBeansFinder.MockProperties<ReplaceWithMock>> mockedBeans) {
         for (Map.Entry<String, DesiredMockitoBeansFinder.MockProperties<ReplaceWithMock>> beanEntry : this.mockedBeans.entrySet()) {
             DesiredMockitoBeansFinder.MockProperties<ReplaceWithMock> mockProperties = beanEntry.getValue();
-            ReplaceWithMock replaceWithMockAnnotation = mockProperties.getAnnotationValues();
+            ReplaceWithMock replaceWithMockAnnotation = mockProperties.getAnnotationInstance();
             context.registerBeanDefinition(beanEntry.getKey(),
                     mockitoBeansDefiner.createMockFactoryBeanDefinition(mockProperties.getMockClass(),
                             replaceWithMockAnnotation.extraInterfaces(),
         }
     }
 
+    private void defineMocksAndSpies(Class<?> clazz) {
+        this.mockedBeans.putAll(mockedBeansFinder.findMockedBeans(clazz));
+        this.spiedBeans.addAll(mockedBeansFinder.findSpiedBeans(clazz));
+    }
+
+    private List<String> generateLocationForMocksAndSpies() {
+        List<String> result = new ArrayList<String>(mockedBeans.size() + spiedBeans.size());
+
+        for (Map.Entry<String, DesiredMockitoBeansFinder.MockProperties<ReplaceWithMock>> mockDefinitionEntry : mockedBeans.entrySet()) {
+            result.add("classpath*:/mock-" + mockDefinitionEntry.getKey() + "=" + mockDefinitionEntry.getValue().getClasspathRepresentation());
+        }
+
+        for (String spiedBean : spiedBeans) {
+            result.add("classpath*:/spy-" + spiedBean);
+        }
+
+        return result;
+    }
+
+    // I know I could use commons or sth but I don't want to introduce more deps than are actually really really needed
+    private <T> List<T> merge(List<T> list1, List<T> list2) {
+        List<T> result = new ArrayList<T>(list1.size() + list2.size());
+
+        result.addAll(list1);
+        result.addAll(list2);
+
+        return result;
+    }
+
+    private String[] addFakeLocationsOfBeansAndSpies(String[] locations) {
+        List<String> locationOfMocksAndSpies = generateLocationForMocksAndSpies();
+        return merge(Arrays.asList(locations), locationOfMocksAndSpies)
+                .toArray(new String[locations.length + locationOfMocksAndSpies.size()]);
+    }
+
     @Override
     protected String[] generateDefaultLocations(Class<?> clazz) {
-        this.mockedBeans = mockedBeansFinder.findMockedBeans(clazz);
-        this.spiedBeans = mockedBeansFinder.findSpiedBeans(clazz);
+        String[] resultingLocations = super.generateDefaultLocations(clazz);
 
-        return super.generateDefaultLocations(clazz);
+        defineMocksAndSpies(clazz);
+
+        return addFakeLocationsOfBeansAndSpies(resultingLocations);
 
     }
 
     @Override
-    protected String[] modifyLocations(Class<?> clazz, String... locations) {
-        this.mockedBeans = mockedBeansFinder.findMockedBeans(clazz);
-        this.spiedBeans = mockedBeansFinder.findSpiedBeans(clazz);
+    protected String[] modifyLocations(Class<?> clazz, String... passedLocations) {
+        String[] resultingLocations = super.modifyLocations(clazz, passedLocations);
 
-        return super.modifyLocations(clazz, locations);
+        defineMocksAndSpies(clazz);
+
+        return addFakeLocationsOfBeansAndSpies(resultingLocations);
     }
 }

springockito-annotations/src/test/java/org/kubek2k/springockito/annotations/contextcache/NoSpringockitoIntegrationTest.java

+package org.kubek2k.springockito.annotations.contextcache;
+
+import junit.framework.Assert;
+import org.kubek2k.springockito.annotations.InnerBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
+import org.testng.annotations.Test;
+
+@ContextConfiguration(locations = {"classpath:/componentScanMockContext.xml", "classpath*:mock=org.kubek2k.springockito"})
+public class NoSpringockitoIntegrationTest extends AbstractTestNGSpringContextTests {
+
+    @Autowired
+    private InnerBean innerBean;
+
+    @Test
+    public void shouldBeAnActualBean() {
+         Assert.assertEquals(InnerBean.class, innerBean.getClass());
+    }
+}

springockito-annotations/src/test/java/org/kubek2k/springockito/annotations/contextcache/SpringockitoIntegrationTest.java

+package org.kubek2k.springockito.annotations.contextcache;
+
+import junit.framework.Assert;
+import org.kubek2k.springockito.annotations.InnerBean;
+import org.kubek2k.springockito.annotations.ReplaceWithMock;
+import org.kubek2k.springockito.annotations.SpringockitoContextLoader;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
+import org.testng.annotations.Test;
+
+@ContextConfiguration(locations = "classpath:/componentScanMockContext.xml", loader = SpringockitoContextLoader.class)
+public class SpringockitoIntegrationTest extends AbstractTestNGSpringContextTests {
+
+    @Autowired
+    @ReplaceWithMock
+    private InnerBean innerBean;
+
+    @Test
+    public void shouldBeAnActualBean() {
+        org.testng.Assert.assertFalse(innerBean.getClass().equals(InnerBean.class));
+    }
+}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.