pbatko avatar pbatko committed 962e377

Start adding support for JavaConfig. Copy springockito classes and resources to springockito-annotations as part of unifying springockito. Refactor springockito-annotations. Add experimental SynchronizedMockMethodInterceptorFilter. Add support for reseting mocks and spy to xml defined mocks and spies.

Comments (0)

Files changed (130)

springockito-annotations/pom.xml

 
     <groupId>org.kubek2k</groupId>
     <artifactId>springockito-annotations</artifactId>
-    <version>1.0.7</version>
+    <version>1.0.9-SNAPSHOT</version>
     <name>Springockito annotations</name>
 
     <parent>

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

+package org.kubek2k.springockito.annotations;
+
+import org.kubek2k.springockito.annotations.internal.Loader;
+import org.springframework.context.support.GenericApplicationContext;
+import org.springframework.test.context.ContextConfigurationAttributes;
+import org.springframework.test.context.support.AnnotationConfigContextLoader;
+
+public class SpringockitoAnnotatedContextLoader extends AnnotationConfigContextLoader{
+
+    private Loader loader = new Loader();
+
+    @Override
+    protected void customizeContext(GenericApplicationContext context) {
+        super.customizeContext(context);
+        loader.registerMocksAndSpies(context);
+    }
+
+    @Override
+    protected Class<?>[] detectDefaultConfigurationClasses(Class<?> declaringClass) {
+        Class<?>[] clazz = super.detectDefaultConfigurationClasses(declaringClass);
+        loader.defineMocksAndSpies(declaringClass);
+        return clazz;
+    }
+
+    @Override
+    public void processContextConfiguration(ContextConfigurationAttributes configAttributes) {
+        super.processContextConfiguration(configAttributes);
+        loader.defineMocksAndSpies(configAttributes.getDeclaringClass());
+    }
+}

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

 package org.kubek2k.springockito.annotations;
 
-import org.kubek2k.springockito.annotations.internal.DesiredMockitoBeansFinder;
-import org.kubek2k.springockito.annotations.internal.definer.MockitoBeansDefiner;
-import org.kubek2k.springockito.annotations.internal.definer.MockitoSpiesDefiner;
-import org.springframework.beans.factory.config.BeanDefinition;
+import org.kubek2k.springockito.annotations.internal.Loader;
 import org.springframework.context.support.GenericApplicationContext;
 import org.springframework.test.context.support.GenericXmlContextLoader;
 
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.TreeSet;
-
 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 TreeMap<String, DesiredMockitoBeansFinder.MockProperties<ReplaceWithMock>>();
-    private Set<String> spiedBeans = new TreeSet<String>();
-
-    private DesiredMockitoBeansFinder mockedBeansFinder = new DesiredMockitoBeansFinder();
-
-    private MockitoBeansDefiner mockitoBeansDefiner = new MockitoBeansDefiner();
-    private MockitoSpiesDefiner mockitoSpiesDefiner = new MockitoSpiesDefiner();
+    private Loader loader = new Loader();
 
     @Override
     protected void customizeContext(GenericApplicationContext context) {
         super.customizeContext(context);
-        registerMocks(context, mockedBeans);
-        registerSpies(context, spiedBeans);
-    }
-
-    private void registerMocks(GenericApplicationContext context,
-                               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.getAnnotationInstance();
-            context.registerBeanDefinition(beanEntry.getKey(),
-                    mockitoBeansDefiner.createMockFactoryBeanDefinition(mockProperties.getMockClass(),
-                            replaceWithMockAnnotation.extraInterfaces(),
-                            replaceWithMockAnnotation.name(),
-                            replaceWithMockAnnotation.defaultAnswer()
-                    ));
-        }
-    }
-
-    private void registerSpies(GenericApplicationContext context, Set<String> spiedBeanNames) {
-        for (String beanName : spiedBeanNames) {
-            BeanDefinition beanDefinition = context.getBeanDefinition(beanName);
-            String wrappedBeanName = beanName + "$$WRAPPED_WITH_SPY";
-            context.registerBeanDefinition(wrappedBeanName, beanDefinition);
-            context.registerBeanDefinition(beanName, mockitoSpiesDefiner.createSpyDefinition(wrappedBeanName));
-        }
-    }
-
-    private void defineMocksAndSpies(Class<?> clazz) {
-        this.mockedBeans.putAll(mockedBeansFinder.findMockedBeans(clazz));
-        this.spiedBeans.addAll(mockedBeansFinder.findSpiedBeans(clazz));
+        loader.registerMocksAndSpies(context);
     }
 
     @Override
     protected String[] generateDefaultLocations(Class<?> clazz) {
         String[] resultingLocations = super.generateDefaultLocations(clazz);
-        defineMocksAndSpies(clazz);
+        loader.defineMocksAndSpies(clazz);
         return resultingLocations;
-
     }
 
     @Override
     protected String[] modifyLocations(Class<?> clazz, String... passedLocations) {
         String[] resultingLocations = super.modifyLocations(clazz, passedLocations);
-        defineMocksAndSpies(clazz);
+        loader.defineMocksAndSpies(clazz);
         return resultingLocations;
     }
 }

springockito-annotations/src/main/java/org/kubek2k/springockito/annotations/experimental/DirtiesMocksTestContextListener.java

 package org.kubek2k.springockito.annotations.experimental;
 
-import org.kubek2k.springockito.annotations.internal.ResettableMock;
+import org.kubek2k.springockito.core.internal.ResettableSpringockito;
 import org.springframework.context.ApplicationContext;
 import org.springframework.test.context.TestContext;
 import org.springframework.test.context.support.AbstractTestExecutionListener;
 
     private void resetMocks(TestContext testContext) {
         ApplicationContext applicationContext = testContext.getApplicationContext();
-        Map<String, ResettableMock> beansOfType = applicationContext.getBeansOfType(ResettableMock.class);
-        for (ResettableMock resettableMock : beansOfType.values()) {
-            resettableMock.resetMock();
+        Map<String, ResettableSpringockito> beansOfType = applicationContext.getBeansOfType(ResettableSpringockito.class);
+        for (ResettableSpringockito resettableSpringockito : beansOfType.values()) {
+            resettableSpringockito.reset();
         }
     }
 }

springockito-annotations/src/main/java/org/kubek2k/springockito/annotations/internal/DefinitionRegistry.java

+package org.kubek2k.springockito.annotations.internal;
+
+import org.kubek2k.springockito.annotations.internal.definitions.SpringockitoDefinition;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class DefinitionRegistry {
+
+    private Map<String, SpringockitoDefinition> springockitoDefinitionMap = new HashMap<String, SpringockitoDefinition>();
+
+    public void registerAll(Set<SpringockitoDefinition> springockitoDefinitions) {
+        for (SpringockitoDefinition springockitoDefinition : springockitoDefinitions) {
+            //TODO: log when overriding
+            springockitoDefinitionMap.put(springockitoDefinition.getTargetBeanName(), springockitoDefinition);
+        }
+    }
+
+    public Iterable<SpringockitoDefinition> getRegistered() {
+        return springockitoDefinitionMap.values();
+    }
+}

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

-package org.kubek2k.springockito.annotations.internal;
-
-import org.kubek2k.springockito.annotations.ReplaceWithMock;
-import org.kubek2k.springockito.annotations.WrapWithSpy;
-import org.kubek2k.springockito.annotations.internal.naming.BeanNameResolver;
-import org.kubek2k.springockito.annotations.internal.naming.BeanNameResolverChainOfResponsibility;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Field;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Set;
-
-public class DesiredMockitoBeansFinder {
-
-    private final BeanNameResolver beanNameResolver = new BeanNameResolverChainOfResponsibility();
-
-    public static class MockProperties<T extends Annotation> {
-
-        private T annotationInstance;
-        private Class<?> mockClass;
-
-        public MockProperties(T annotationInstance, Class<?> mockClass) {
-            this.annotationInstance = annotationInstance;
-            this.mockClass = mockClass;
-        }
-
-        public T getAnnotationInstance() {
-            return annotationInstance;
-        }
-
-        public Class<?> getMockClass() {
-            return mockClass;
-        }
-
-    }
-
-    public Map<String, MockProperties<ReplaceWithMock>> findMockedBeans(Class<?> clazz) {
-        Map<String, MockProperties<ReplaceWithMock>> mockedBeans = new LinkedHashMap<String, MockProperties<ReplaceWithMock>>();
-        for (Field field : clazz.getDeclaredFields()) {
-            ReplaceWithMock annotationInstance = field.getAnnotation(ReplaceWithMock.class);
-            if (annotationInstance != null) {
-                String beanName = getBeanName(field);
-                MockProperties<ReplaceWithMock> mockProperties = new MockProperties<ReplaceWithMock>(annotationInstance, field.getType());
-                mockedBeans.put(beanName, mockProperties);
-            }
-        }
-        return mockedBeans;
-    }
-
-    public Set<String> findSpiedBeans(Class<?> clazz) {
-        Set<String> mockedBeans = new HashSet<String>();
-        for (Field field : clazz.getDeclaredFields()) {
-            Annotation replaceWithMockAnnotation = field.getAnnotation(WrapWithSpy.class);
-            if (replaceWithMockAnnotation != null) {
-                String beanName = getBeanName(field);
-                mockedBeans.add(beanName);
-            }
-        }
-        return mockedBeans;
-    }
-
-    private String getBeanName(Field field) {
-        return beanNameResolver.retrieveBeanName(field);
-    }
-}

springockito-annotations/src/main/java/org/kubek2k/springockito/annotations/internal/Loader.java

+package org.kubek2k.springockito.annotations.internal;
+
+import org.kubek2k.springockito.annotations.internal.definitions.SpringockitoDefinition;
+import org.kubek2k.springockito.annotations.internal.definitions.bean.SpringockitoBeanDefinition;
+import org.springframework.context.support.GenericApplicationContext;
+
+public class Loader {
+
+    private DefinitionRegistry definitionRegistry = new DefinitionRegistry();
+    private SpringockitoDefinitionFinder springockitoDefinitionFinder = new SpringockitoDefinitionFinder();
+
+    public void defineMocksAndSpies(Class<?> clazz) {
+        this.definitionRegistry.registerAll(springockitoDefinitionFinder.findSpringockitoDefinitions(clazz));
+    }
+
+    public void registerMocksAndSpies(GenericApplicationContext context) {
+        for (SpringockitoDefinition springockitoDefinition : definitionRegistry.getRegistered()) {
+            SpringockitoBeanDefinition beanDefinition = springockitoDefinition.createSpringockitoBeanDefinition();
+            context.registerBeanDefinition(beanDefinition.getSpringBeanName(), beanDefinition.getSpringBeanDefinition());
+        }
+    }
+}

springockito-annotations/src/main/java/org/kubek2k/springockito/annotations/internal/MockitoMockSettings.java

+package org.kubek2k.springockito.annotations.internal;
+
+import org.mockito.Answers;
+import org.mockito.MockSettings;
+import org.mockito.internal.creation.MockSettingsImpl;
+
+public class MockitoMockSettings {
+
+    public static final MockitoMockSettings DEFAULT = new MockitoMockSettings();
+    private Class<?>[] extraInterfaces;
+    private String mockName;
+    private Answers defaultAnswer;
+
+    public MockSettings getMockSettings() {
+        return createMockSettings();
+    }
+
+    private MockSettings createMockSettings() {
+        MockSettings mockSettings = new MockSettingsImpl();
+
+        if (extraInterfaces != null && extraInterfaces.length > 0) {
+            mockSettings.extraInterfaces(extraInterfaces);
+        }
+
+        if (defaultAnswer != null) {
+            mockSettings.defaultAnswer(defaultAnswer.get());
+        } else {
+            mockSettings.defaultAnswer(Answers.RETURNS_DEFAULTS.get());
+        }
+
+        if (mockName != null) {
+            mockSettings.name(mockName);
+        }
+        return mockSettings;
+    }
+
+    public MockitoMockSettings withExtraInterfaces(Class<?>[] extraInterfaces) {
+        this.extraInterfaces = extraInterfaces;
+        return this;
+    }
+
+    public MockitoMockSettings withMockName(String mockName) {
+        this.mockName = mockName;
+        return this;
+    }
+
+    public MockitoMockSettings withDefaultAnswer(Answers defaultAnswer) {
+        this.defaultAnswer = defaultAnswer;
+        return this;
+    }
+}

springockito-annotations/src/main/java/org/kubek2k/springockito/annotations/internal/ResettableMock.java

-package org.kubek2k.springockito.annotations.internal;
-
-public interface ResettableMock {
-    void resetMock();
-}

springockito-annotations/src/main/java/org/kubek2k/springockito/annotations/internal/SpringockitoDefinitionFinder.java

+package org.kubek2k.springockito.annotations.internal;
+
+import org.kubek2k.springockito.annotations.ReplaceWithMock;
+import org.kubek2k.springockito.annotations.WrapWithSpy;
+import org.kubek2k.springockito.annotations.internal.definitions.MockDefinition;
+import org.kubek2k.springockito.annotations.internal.definitions.SpringockitoDefinition;
+import org.kubek2k.springockito.annotations.internal.definitions.SpyDefinition;
+import org.kubek2k.springockito.annotations.internal.naming.BeanNameResolver;
+import org.kubek2k.springockito.annotations.internal.naming.BeanNameResolverChainOfResponsibility;
+
+import java.lang.reflect.Field;
+import java.util.HashSet;
+import java.util.Set;
+
+public class SpringockitoDefinitionFinder {
+
+    private BeanNameResolver beanNameResolver = new BeanNameResolverChainOfResponsibility();
+
+    public Set<SpringockitoDefinition> findSpringockitoDefinitions(Class<?> clazz) {
+        Set<SpringockitoDefinition> springockitoDefinitions = new HashSet<SpringockitoDefinition>();
+        for (Field field : clazz.getDeclaredFields()) {
+            if (field.isAnnotationPresent(ReplaceWithMock.class)) {
+                springockitoDefinitions.add(newMockDefinition(field));
+            } else if (field.isAnnotationPresent(WrapWithSpy.class)) {
+                springockitoDefinitions.add(newSpyDefinition(field));
+            }
+        }
+        return springockitoDefinitions;
+    }
+
+    private SpyDefinition newSpyDefinition(Field field) {
+        return new SpyDefinition()
+                .withTargetBeanName(resolveBeanName(field));
+    }
+
+    private MockDefinition newMockDefinition(Field field) {
+        return new MockDefinition()
+                .withAnnotationInstance(field.getAnnotation(ReplaceWithMock.class))
+                .withMockClass(field.getType())
+                .withTargetBeanName(resolveBeanName(field));
+    }
+
+    private String resolveBeanName(Field field) {
+        return beanNameResolver.retrieveBeanName(field);
+    }
+}

springockito-annotations/src/main/java/org/kubek2k/springockito/annotations/internal/definer/Definer.java

+package org.kubek2k.springockito.annotations.internal.definer;
+
+import org.kubek2k.springockito.annotations.internal.definitions.SpringockitoDefinition;
+import org.kubek2k.springockito.annotations.internal.definitions.bean.SpringockitoBeanDefinition;
+import org.springframework.beans.factory.config.BeanDefinition;
+
+public abstract class Definer<T extends SpringockitoDefinition> {
+
+    public SpringockitoBeanDefinition define(T springockitoDefinition) {
+        return new SpringockitoBeanDefinition()
+                .withSpringBeanDefinition(getSpringBeanDefinition(springockitoDefinition))
+                .withSpringBeanName(getSpringBeanName(springockitoDefinition));
+    }
+
+    protected abstract String getSpringBeanName(T springockitoDefinition);
+
+    protected abstract BeanDefinition getSpringBeanDefinition(T springockitoDefinition);
+}

springockito-annotations/src/main/java/org/kubek2k/springockito/annotations/internal/definer/MockDefiner.java

+package org.kubek2k.springockito.annotations.internal.definer;
+
+import org.kubek2k.springockito.annotations.internal.definitions.MockDefinition;
+import org.kubek2k.springockito.core.internal.mock.MockFactorySpringockito;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+
+public class MockDefiner extends Definer<MockDefinition>{
+
+    private static final MockDefiner INSTANCE = new MockDefiner();
+
+    private MockDefiner(){}
+
+    public static MockDefiner getInstance(){
+        return INSTANCE;
+    }
+
+    @Override
+    protected String getSpringBeanName(MockDefinition mockDefinition) {
+        return mockDefinition.getTargetBeanName();
+    }
+
+    @Override
+    protected BeanDefinition getSpringBeanDefinition(MockDefinition mockDefinition) {
+        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(MockFactorySpringockito.class.getCanonicalName())
+                .addPropertyValue("mockClass",mockDefinition.getMockClass())
+                .addPropertyValue("mockitoMockSettings",mockDefinition.getMockitoMockSettings())
+                .getBeanDefinition();
+        beanDefinition.setPrimary(true);
+        return beanDefinition;
+    }
+}

springockito-annotations/src/main/java/org/kubek2k/springockito/annotations/internal/definer/MockitoBeansDefiner.java

-package org.kubek2k.springockito.annotations.internal.definer;
-
-import org.kubek2k.springockito.annotations.internal.factory.MockFactoryBean;
-import org.mockito.Answers;
-import org.springframework.beans.factory.support.AbstractBeanDefinition;
-import org.springframework.beans.factory.support.BeanDefinitionBuilder;
-
-public class MockitoBeansDefiner {
-    public AbstractBeanDefinition createMockFactoryBeanDefinition(Class<?> mockClass, Class[] extraInterfaces, String mockName, Answers defaultAnswer) {
-        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(MockFactoryBean.class.getCanonicalName())
-                .addConstructorArgValue(mockClass)
-                .addConstructorArgValue(extraInterfaces)
-                .addConstructorArgValue(mockName)
-                .addConstructorArgValue(defaultAnswer)
-                .getBeanDefinition();
-        beanDefinition.setPrimary(true);
-        return beanDefinition;
-    }
-}

springockito-annotations/src/main/java/org/kubek2k/springockito/annotations/internal/definer/MockitoSpiesDefiner.java

-package org.kubek2k.springockito.annotations.internal.definer;
-
-import org.kubek2k.springockito.annotations.internal.factory.SpyFactoryBean;
-import org.springframework.beans.factory.support.AbstractBeanDefinition;
-import org.springframework.beans.factory.support.BeanDefinitionBuilder;
-
-public class MockitoSpiesDefiner {
-
-    public AbstractBeanDefinition createSpyDefinition(String wrappedBeanName) {
-        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
-                .rootBeanDefinition(SpyFactoryBean.class.getCanonicalName())
-                .addConstructorArgReference(wrappedBeanName)
-                .getBeanDefinition();
-        beanDefinition.setPrimary(true);
-        return beanDefinition;
-    }
-
-}

springockito-annotations/src/main/java/org/kubek2k/springockito/annotations/internal/definer/SpyDefiner.java

+package org.kubek2k.springockito.annotations.internal.definer;
+
+import org.kubek2k.springockito.annotations.internal.definitions.SpyDefinition;
+import org.kubek2k.springockito.core.internal.spy.SpySpringockitoPostProcessor;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+
+public class SpyDefiner extends Definer<SpyDefinition> {
+
+    public static final SpyDefiner INSTANCE = new SpyDefiner();
+
+    private SpyDefiner(){}
+
+    public static SpyDefiner getInstance(){
+        return INSTANCE;
+    }
+
+    @Override
+    protected String getSpringBeanName(SpyDefinition springockitoDefinition) {
+        return springockitoDefinition.getTargetBeanName() + "$$POST_PROCESSOR_SPY";
+    }
+
+    @Override
+    protected BeanDefinition getSpringBeanDefinition(SpyDefinition spyDefinition) {
+        return BeanDefinitionBuilder
+                .rootBeanDefinition(SpySpringockitoPostProcessor.class.getCanonicalName())
+                .addPropertyValue("beanName", spyDefinition.getTargetBeanName())
+                .getBeanDefinition();
+    }
+}

springockito-annotations/src/main/java/org/kubek2k/springockito/annotations/internal/definitions/AbstractDefinition.java

+package org.kubek2k.springockito.annotations.internal.definitions;
+
+public abstract class AbstractDefinition<T> implements SpringockitoDefinition {
+
+    private String targetBeanName;
+
+    protected abstract T getThis();
+
+    public String getTargetBeanName() {
+        return targetBeanName;
+    }
+
+    public T withTargetBeanName(String targetBeanName) {
+        this.targetBeanName = targetBeanName;
+        return getThis();
+    }
+}

springockito-annotations/src/main/java/org/kubek2k/springockito/annotations/internal/definitions/MockDefinition.java

+package org.kubek2k.springockito.annotations.internal.definitions;
+
+import org.kubek2k.springockito.annotations.internal.MockitoMockSettings;
+import org.kubek2k.springockito.annotations.ReplaceWithMock;
+import org.kubek2k.springockito.annotations.internal.definer.MockDefiner;
+import org.kubek2k.springockito.annotations.internal.definitions.bean.SpringockitoBeanDefinition;
+
+public class MockDefinition extends AbstractDefinition<MockDefinition>{
+
+    private ReplaceWithMock annotationInstance;
+    private Class<?> mockClass;
+
+    public Class<?> getMockClass() {
+        return mockClass;
+    }
+
+    public MockitoMockSettings getMockitoMockSettings() {
+        return new MockitoMockSettings()
+                .withMockName(annotationInstance.name())
+                .withDefaultAnswer(annotationInstance.defaultAnswer())
+                .withExtraInterfaces(annotationInstance.extraInterfaces());
+    }
+
+    public MockDefinition withAnnotationInstance(ReplaceWithMock annotationInstance) {
+        this.annotationInstance = annotationInstance;
+        return this;
+    }
+
+    public MockDefinition withMockClass(Class<?> mockClass) {
+        this.mockClass = mockClass;
+        return this;
+    }
+
+    public SpringockitoBeanDefinition createSpringockitoBeanDefinition() {
+        return MockDefiner.getInstance().define(this);
+    }
+
+    @Override
+    protected MockDefinition getThis() {
+        return this;
+    }
+}

springockito-annotations/src/main/java/org/kubek2k/springockito/annotations/internal/definitions/SpringockitoDefinition.java

+package org.kubek2k.springockito.annotations.internal.definitions;
+
+import org.kubek2k.springockito.annotations.internal.definitions.bean.SpringockitoBeanDefinition;
+
+public interface SpringockitoDefinition {
+
+    String getTargetBeanName();
+
+    SpringockitoBeanDefinition createSpringockitoBeanDefinition();
+}

springockito-annotations/src/main/java/org/kubek2k/springockito/annotations/internal/definitions/SpyDefinition.java

+package org.kubek2k.springockito.annotations.internal.definitions;
+
+import org.kubek2k.springockito.annotations.internal.definer.SpyDefiner;
+import org.kubek2k.springockito.annotations.internal.definitions.bean.SpringockitoBeanDefinition;
+
+public class SpyDefinition extends AbstractDefinition<SpyDefinition> {
+
+    public SpringockitoBeanDefinition createSpringockitoBeanDefinition(){
+        return SpyDefiner.getInstance().define(this);
+    }
+
+    @Override
+    protected SpyDefinition getThis() {
+        return this;
+    }
+}

springockito-annotations/src/main/java/org/kubek2k/springockito/annotations/internal/definitions/bean/SpringockitoBeanDefinition.java

+package org.kubek2k.springockito.annotations.internal.definitions.bean;
+
+import org.springframework.beans.factory.config.BeanDefinition;
+
+public class SpringockitoBeanDefinition {
+
+    private String springBeanName;
+    private BeanDefinition springBeanDefinition;
+
+    public String getSpringBeanName() {
+        return springBeanName;
+    }
+
+    public SpringockitoBeanDefinition withSpringBeanName(String springBeanName) {
+        this.springBeanName = springBeanName;
+        return this;
+    }
+
+    public BeanDefinition getSpringBeanDefinition() {
+        return springBeanDefinition;
+    }
+
+    public SpringockitoBeanDefinition withSpringBeanDefinition(BeanDefinition springBeanDefinition) {
+        this.springBeanDefinition = springBeanDefinition;
+        return this;
+    }
+}

springockito-annotations/src/main/java/org/kubek2k/springockito/annotations/internal/factory/MockFactoryBean.java

-package org.kubek2k.springockito.annotations.internal.factory;
-
-import org.kubek2k.springockito.annotations.internal.ResettableMock;
-import org.mockito.Answers;
-import org.mockito.MockSettings;
-import org.mockito.Mockito;
-import org.mockito.internal.creation.MockSettingsImpl;
-import org.springframework.beans.factory.FactoryBean;
-
-
-public class MockFactoryBean<T> implements FactoryBean<T>, ResettableMock {
-
-    private Class<T> mockClass;
-    private final Class[] extraInterfaces;
-    private final String mockName;
-    private final Answers defaultAnswer;
-    private T instance;
-
-    public MockFactoryBean(Class<T> mockClass, Class[] extraInterfaces, String mockName, Answers defaultAnswer) {
-        this.mockClass = mockClass;
-        this.extraInterfaces = extraInterfaces;
-        this.mockName = mockName;
-        this.defaultAnswer = defaultAnswer;
-    }
-
-    public Class<? extends T> getObjectType() {
-        return mockClass;
-    }
-
-    public boolean isSingleton() {
-        return true;
-    }
-
-    public T getObject() throws Exception {
-        if (instance == null) {
-            instance = createInstance();
-        }
-        return instance;
-    }
-
-    private T createInstance() {
-        MockSettings mockSettings = new MockSettingsImpl();
-
-        if (extraInterfaces.length > 0) {
-            mockSettings = mockSettings.extraInterfaces(extraInterfaces);
-        }
-
-        if (defaultAnswer != null) {
-            mockSettings = mockSettings.defaultAnswer(defaultAnswer.get());
-        }
-
-        if (mockName != null) {
-            mockSettings = mockSettings.name(mockName);
-        }
-
-        return Mockito.mock(mockClass, mockSettings);
-    }
-
-    public void resetMock() {
-        T object = null;
-        try {
-            object = getObject();
-            Mockito.reset(object);
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-    }
-}

springockito-annotations/src/main/java/org/kubek2k/springockito/annotations/internal/factory/SpyFactoryBean.java

-package org.kubek2k.springockito.annotations.internal.factory;
-
-import org.kubek2k.springockito.annotations.internal.ResettableMock;
-import org.mockito.Mockito;
-import org.springframework.beans.factory.FactoryBean;
-
-public class SpyFactoryBean<T> implements FactoryBean<T>, ResettableMock {
-
-    private T wrappedInstance;
-
-    private T spyInstance;
-
-    public SpyFactoryBean(T wrappedInstance) {
-        this.wrappedInstance = wrappedInstance;
-    }
-
-    public T getObject() throws Exception {
-        if (spyInstance == null) {
-            spyInstance = Mockito.spy(wrappedInstance);
-        }
-        return spyInstance;
-    }
-
-    @SuppressWarnings("unchecked")
-    public Class<? extends T> getObjectType() {
-        return (Class<? extends T>) wrappedInstance.getClass();
-    }
-
-    public boolean isSingleton() {
-        return true;
-    }
-
-    public void resetMock() {
-        T object = null;
-        try {
-            object = getObject();
-            Mockito.reset(object);
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-    }
-}

springockito-annotations/src/main/java/org/kubek2k/springockito/annotations/internal/naming/BeanNameResolverChainOfResponsibility.java

 
 public class BeanNameResolverChainOfResponsibility implements BeanNameResolver {
 
-    List<AbstractBeanNameResolver> resolversChain;
-    AbstractBeanNameResolver defaultResolver;
+    private List<AbstractBeanNameResolver> resolversChain;
 
     public BeanNameResolverChainOfResponsibility() {
-        this.defaultResolver = new ExplicitBeanNameStrategyBeanNameResolver();
         this.resolversChain = new ArrayList<AbstractBeanNameResolver>();
         Collections.addAll(resolversChain,
                 new ExplicitBeanNameNameResolver(),

springockito-annotations/src/main/java/org/kubek2k/springockito/core/internal/ResettableSpringockito.java

+package org.kubek2k.springockito.core.internal;
+
+public interface ResettableSpringockito {
+
+    void reset();
+}

springockito-annotations/src/main/java/org/kubek2k/springockito/core/internal/mock/MockFactorySpringockito.java

+package org.kubek2k.springockito.core.internal.mock;
+
+import org.kubek2k.springockito.annotations.internal.MockitoMockSettings;
+import org.kubek2k.springockito.core.internal.ResettableSpringockito;
+import org.mockito.MockSettings;
+import org.mockito.Mockito;
+import org.springframework.beans.factory.FactoryBean;
+
+
+public class MockFactorySpringockito<T> implements FactoryBean<T>, ResettableSpringockito {
+
+    protected Class<T> mockClass;
+    protected MockitoMockSettings mockitoMockSettings;
+    protected T instance;
+
+    public Class<? extends T> getObjectType() {
+        return mockClass;
+    }
+
+    public boolean isSingleton() {
+        return true;
+    }
+
+    public T getObject() throws Exception {
+        if (instance == null) {
+            instance = Mockito.mock(mockClass, getMockSettings());
+        }
+        return instance;
+    }
+
+    private MockSettings getMockSettings() {
+        if(mockitoMockSettings == null){
+            mockitoMockSettings = MockitoMockSettings.DEFAULT;
+        }
+        return mockitoMockSettings.getMockSettings();
+    }
+
+    public void setMockClass(Class<T> mockClass) {
+        this.mockClass = mockClass;
+    }
+
+    public void setMockitoMockSettings(MockitoMockSettings mockitoMockSettings) {
+        this.mockitoMockSettings = mockitoMockSettings;
+    }
+
+    public void reset() {
+        try {
+            Mockito.<Object>reset(getObject());
+        } catch (Exception e) {
+            //TODO: throw runtime?
+            e.printStackTrace();
+        }
+    }
+}

springockito-annotations/src/main/java/org/kubek2k/springockito/core/internal/mock/SynchronizedMockFactorySpringockito.java

+package org.kubek2k.springockito.core.internal.mock;
+
+import org.kubek2k.springockito.annotations.internal.MockitoMockSettings;
+import org.mockito.internal.InvocationNotifierHandler;
+import org.mockito.internal.MockHandler;
+import org.mockito.internal.creation.MockSettingsImpl;
+import org.mockito.internal.creation.jmock.ClassImposterizer;
+
+public class SynchronizedMockFactorySpringockito<T> extends MockFactorySpringockito<T> {
+
+    private boolean threadSafe;
+
+    public T getObject() throws Exception {
+        if (instance == null) {
+            if(threadSafe){
+                instance = getMockWithSynchronizedMethodIntercepting();
+            } else {
+                return super.getObject();
+            }
+        }
+        return instance;
+    }
+
+    private T getMockWithSynchronizedMethodIntercepting() {
+        SynchronizedMockMethodInterceptorFilter synchronizedMethodInterceptorFilter = createSynchronizedMethodInterceptorFilter();
+        return ClassImposterizer.INSTANCE.imposterise(synchronizedMethodInterceptorFilter, mockClass, new Class[0]);
+    }
+
+    /**
+     * Inspired by Mockito internals
+     */
+    private SynchronizedMockMethodInterceptorFilter createSynchronizedMethodInterceptorFilter() {
+        MockSettingsImpl mockSettings = (MockSettingsImpl)MockitoMockSettings.DEFAULT.getMockSettings();
+        MockHandler<T> mockHandler = new MockHandler<T>(mockSettings);
+        InvocationNotifierHandler<T> invocationNotifierHandler = new InvocationNotifierHandler<T>(mockHandler, mockSettings);
+        return new SynchronizedMockMethodInterceptorFilter(invocationNotifierHandler, mockSettings);
+    }
+
+    public void setThreadSafe(boolean threadSafe) {
+        this.threadSafe = threadSafe;
+    }
+}

springockito-annotations/src/main/java/org/kubek2k/springockito/core/internal/mock/SynchronizedMockMethodInterceptorFilter.java

+package org.kubek2k.springockito.core.internal.mock;
+
+import org.mockito.cglib.proxy.MethodProxy;
+import org.mockito.internal.MockitoInvocationHandler;
+import org.mockito.internal.creation.MethodInterceptorFilter;
+import org.mockito.internal.creation.MockSettingsImpl;
+
+import java.lang.reflect.Method;
+
+public class SynchronizedMockMethodInterceptorFilter extends MethodInterceptorFilter {
+
+    public SynchronizedMockMethodInterceptorFilter(MockitoInvocationHandler handler, MockSettingsImpl mockSettings) {
+        super(handler, mockSettings);
+    }
+
+    @Override
+    public synchronized Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
+        return super.intercept(proxy, method, args, methodProxy);
+    }
+}

springockito-annotations/src/main/java/org/kubek2k/springockito/core/internal/spy/SpySpringockitoPostProcessor.java

+package org.kubek2k.springockito.core.internal.spy;
+
+import org.kubek2k.springockito.core.internal.ResettableSpringockito;
+import org.mockito.Mockito;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+
+public class SpySpringockitoPostProcessor implements BeanPostProcessor,ResettableSpringockito {
+
+    private String beanName;
+    private Object spy;
+
+    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+        return bean;
+    }
+
+    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+        if (this.beanName.equals(beanName)) {
+            spy = Mockito.spy(bean);
+            return spy;
+        } else {
+            return bean;
+        }
+    }
+
+    public void setBeanName(String matchingName) {
+        this.beanName = matchingName;
+    }
+
+    public void reset() {
+        try {
+            Mockito.reset(spy);
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new RuntimeException(e);
+        }
+    }
+}

springockito-annotations/src/main/java/org/kubek2k/springockito/xml/MockitoMockBeanDefinitionParser.java

+package org.kubek2k.springockito.xml;
+
+import org.kubek2k.springockito.core.internal.mock.SynchronizedMockFactorySpringockito;
+import org.springframework.beans.factory.parsing.BeanComponentDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
+import org.w3c.dom.Element;
+
+import static java.lang.Boolean.valueOf;
+
+public class MockitoMockBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
+    
+    @Override
+    protected String getBeanClassName(Element element) {
+        return SynchronizedMockFactorySpringockito.class.getCanonicalName();
+    }
+    
+    @Override
+    protected void doParse(Element element, BeanDefinitionBuilder builder) {
+        String threadSafe = element.getAttribute("threadSafe");
+        builder.addPropertyValue("mockClass",element.getAttribute("class"))
+                .addPropertyValue("threadSafe", valueOf(threadSafe));
+    }
+
+    @Override
+    protected void postProcessComponentDefinition(BeanComponentDefinition componentDefinition) {
+        super.postProcessComponentDefinition(componentDefinition);
+        componentDefinition.getBeanDefinition().setPrimary(true);
+    }
+}

springockito-annotations/src/main/java/org/kubek2k/springockito/xml/MockitoNamespaceHandler.java

+package org.kubek2k.springockito.xml;
+
+import org.springframework.beans.factory.xml.NamespaceHandler;
+import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
+
+public class MockitoNamespaceHandler extends NamespaceHandlerSupport implements NamespaceHandler {
+
+    public void init() {
+        registerBeanDefinitionParser("mock", new MockitoMockBeanDefinitionParser());
+        registerBeanDefinitionParser("spy", new MockitoSpyBeanDefinitionParser());
+    }
+}

springockito-annotations/src/main/java/org/kubek2k/springockito/xml/MockitoSpyBeanDefinitionParser.java

+package org.kubek2k.springockito.xml;
+
+import org.kubek2k.springockito.core.internal.spy.SpySpringockitoPostProcessor;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
+import org.w3c.dom.Element;
+
+public class MockitoSpyBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
+
+    @Override
+    protected String getBeanClassName(Element element) {
+        return SpySpringockitoPostProcessor.class.getCanonicalName();
+    }
+
+    @Override
+    protected void doParse(Element element, BeanDefinitionBuilder beanBuilder) {
+        beanBuilder.addPropertyValue("beanName", element.getAttribute("beanName"));
+    }
+    
+    @Override
+    protected boolean shouldGenerateIdAsFallback() {
+        return true;
+    }
+}

springockito-annotations/src/main/resources/META-INF/spring.handlers

+http\://www.mockito.org/spring/mockito=org.kubek2k.springockito.xml.MockitoNamespaceHandler

springockito-annotations/src/main/resources/META-INF/spring.schemas

+http\://www.mockito.org/spring/mockito.xsd=spring/mockito.xsd

springockito-annotations/src/main/resources/spring/mockito.xsd

+<?xml version="1.0" encoding="UTF-8"?>
+<xsd:schema xmlns="http://www.mockito.org/spring/mockito"
+            xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+            xmlns:beans="http://www.springframework.org/schema/beans"
+            targetNamespace="http://www.mockito.org/spring/mockito"
+            elementFormDefault="qualified"
+            attributeFormDefault="unqualified">
+
+    <xsd:import namespace="http://www.springframework.org/schema/beans"
+                schemaLocation="http://www.springframework.org/schema/beans/spring-beans.xsd"/>
+
+    <xsd:element name="mock">
+        <xsd:complexType>
+            <xsd:complexContent>
+                <xsd:extension base="beans:identifiedType">
+                    <xsd:attribute name="class" type="xsd:string" use="required"/>
+                    <xsd:attribute name="threadSafe" type="xsd:boolean" use="optional" default="false"/>
+                </xsd:extension>
+            </xsd:complexContent>
+
+        </xsd:complexType>
+    </xsd:element>
+
+    <xsd:element name="spy">
+        <xsd:complexType>
+            <xsd:attribute name="beanName" type="xsd:string" use="required"/>
+        </xsd:complexType>
+    </xsd:element>
+
+</xsd:schema>

springockito-annotations/src/test/java/org/kubek2k/mockito/spring/MockitoMockAutowiringIntegrationTest.java

+package org.kubek2k.mockito.spring;
+
+public class MockitoMockAutowiringIntegrationTest {
+
+}

springockito-annotations/src/test/java/org/kubek2k/mockito/spring/MockitoMockHandlerComponentScanIntegrationTest.java

+package org.kubek2k.mockito.spring;
+
+import org.kubek2k.mockito.spring.testbeans.BeanAutowiringMock;
+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;
+
+import static org.testng.Assert.assertNotNull;
+
+@ContextConfiguration(locations={"classpath:spring/mockitoComponentScanContext.xml"})
+public class MockitoMockHandlerComponentScanIntegrationTest extends AbstractTestNGSpringContextTests {
+
+    @Autowired
+    private BeanAutowiringMock beanAutowiringMock;
+
+    @Test
+    public void shouldAutowireMocksInSpringBeansWhenUsingComponentScan() {
+        assertNotNull(beanAutowiringMock);
+        assertNotNull(beanAutowiringMock.getInterfaceToBeMocked());
+    }
+}

springockito-annotations/src/test/java/org/kubek2k/mockito/spring/MockitoMockHandlerIntegrationTest.java

+package org.kubek2k.mockito.spring;
+
+import org.kubek2k.mockito.spring.testbeans.BeanToBeSpiedOrMockedAndStubbed;
+import org.mockito.cglib.proxy.Factory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
+import org.testng.annotations.Test;
+
+import javax.annotation.Resource;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Matchers.anyString;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+
+@ContextConfiguration(locations = {"classpath*:/spring/mockitoContext.xml"})
+public class MockitoMockHandlerIntegrationTest extends AbstractTestNGSpringContextTests {
+
+    @Autowired
+    private SomeFancyClass someFancyClass;
+
+    @Autowired
+    @Qualifier("someFancyClass")
+    private SomeFancyClass someFancyClass2;
+
+    @Resource
+    private BeanToBeSpiedOrMockedAndStubbed beanToBeMockedAndStubbed;
+
+    @Test
+    public void shouldLoadMockitoMock() {
+        assertNotNull(someFancyClass);
+        assertTrue(someFancyClass instanceof Factory);
+
+        assertNotNull(someFancyClass2);
+        assertTrue(someFancyClass2 instanceof Factory);
+
+    }
+
+    @Test
+    public void shouldAllowForMocksTeBeStubbedUsingMockitoMatchers() {
+        //given
+        String fixedReturnValue = "fixedReturnValue";
+        given(beanToBeMockedAndStubbed.methodWithArgument(anyString()))
+                .willReturn(fixedReturnValue);
+
+        //when
+        String returnedString = beanToBeMockedAndStubbed.methodWithArgument("someString");
+
+        //then
+        assertThat(returnedString)
+                .isEqualTo(fixedReturnValue);
+    }
+}

springockito-annotations/src/test/java/org/kubek2k/mockito/spring/MockitoSpyHandlerIntegrationTest.java

+package org.kubek2k.mockito.spring;
+
+import org.kubek2k.mockito.spring.testbeans.BeanToBeInjectedWithSpy;
+import org.kubek2k.mockito.spring.testbeans.BeanToBeSpiedOrMockedAndStubbed;
+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;
+
+import javax.annotation.Resource;
+import java.util.Date;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+@ContextConfiguration(locations = {"classpath*:/spring/parentContext.xml", "classpath*:/spring/mockitoSpyContext.xml"})
+public class MockitoSpyHandlerIntegrationTest extends AbstractTestNGSpringContextTests {
+
+    @Autowired
+    private Date dateToBeSpied;
+
+    @Resource
+    private BeanToBeSpiedOrMockedAndStubbed beanToBeSpiedAndStubbed;
+
+
+    @Resource
+    BeanToBeInjectedWithSpy beanToBeInjectedWithSpy;
+
+
+    @Test
+    public void shouldLoadMockitoSpy() {
+        dateToBeSpied.compareTo(new Date());
+        verify(dateToBeSpied).compareTo(isA(Date.class));
+    }
+
+    @Test
+    public void shouldAllowForSpiesTeBeStubbedUsingMockitoMatchers() {
+        //given
+        String fixedReturnValue = "fixedReturnValue";
+        given(beanToBeSpiedAndStubbed.methodWithArgument(anyString()))
+                .willReturn(fixedReturnValue);
+
+        //when
+        String returnedString = beanToBeSpiedAndStubbed.methodWithArgument("someString");
+
+        //then
+        assertThat(returnedString)
+                .isEqualTo(fixedReturnValue);
+    }
+
+    @Test
+    public void shouldInjectSpyOfTheBeanInsteadOfOriginalOneEverywhere() {
+        //given
+        int expectedAmountOfSpyMethodInvocations = 2;
+
+        //when
+        beanToBeInjectedWithSpy.callMethodWithoutArgumentsOnInjectedBeanTwice();
+
+        //then
+        verify(beanToBeSpiedAndStubbed, times(expectedAmountOfSpyMethodInvocations))
+                .methodWithoutArgument();
+    }
+}

springockito-annotations/src/test/java/org/kubek2k/mockito/spring/MultiThreadingIntegrationTest.java

+package org.kubek2k.mockito.spring;
+
+import org.junit.Ignore;
+import org.kubek2k.mockito.spring.testbeans.BeanAutowiringMock;
+import org.kubek2k.mockito.spring.testbeans.InterfaceToBeMocked;
+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;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+@ContextConfiguration(locations = { "classpath:spring/mockitoComponentScanContext.xml" })
+public class MultiThreadingIntegrationTest extends AbstractTestNGSpringContextTests {
+
+    @Autowired
+    private BeanAutowiringMock beanAutowiringMock;
+
+    @Autowired
+    private InterfaceToBeMocked interfaceToBeMocked;
+
+    /**
+     * We want to have a situation when two separately run tests have separate
+     * mocks injected. I have to use a new thread to spawn tests - it's
+     * something like a junittestrunner simulator - it's caused by the fact that
+     * we'll use {@link InheritableThreadLocal} to keep an instance of current
+     * mocks - please
+     * {@link org.kubek2k.mockito.spring.MultiThreadingIntegrationTest#shouldInheritMocksWhenCodeThatIsBeingSpawnedByTestSpawnsANewThreads()}
+     */
+    @Test
+    @Ignore("This behaviour appears to be a bit esoteric. Why should mock be able to behave differtly" +
+            "in different threads? It rather seem that mock behaviour should be stubbed in front of test " +
+            "and then verfied but not changed. The synchronization issue is another matter. Springockito can " +
+            "consider supporting mock which serializes access to itself")
+    public void shouldAllowConcurrentAccessToMockitoMocks() throws InterruptedException {
+        final AtomicBoolean test1AssertionOutcome = new AtomicBoolean(false);
+        final AtomicBoolean test2AssertionOutcome = new AtomicBoolean(false);
+
+        Thread testRunner = new Thread() {
+            @Override
+            public void run() {
+                Thread test1Runner = new Thread() {
+                    @Override
+                    public void run() {
+                        when(interfaceToBeMocked.getValue()).thenReturn(1);
+                        assertAndSetOutcomeVariable(beanAutowiringMock.getValue(), 1, test1AssertionOutcome);
+                    }
+
+                };
+
+                Thread test2Runner = new Thread() {
+                    @Override
+                    public void run() {
+                        when(interfaceToBeMocked.getValue()).thenReturn(2);
+                        assertAndSetOutcomeVariable(beanAutowiringMock.getValue(), 2, test2AssertionOutcome);
+                    }
+                };
+
+                test1Runner.start();
+                test2Runner.start();
+
+                try {
+                    test1Runner.join();
+                    test2Runner.join();
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                    test1AssertionOutcome.set(false);
+                    test2AssertionOutcome.set(false);
+                }
+            }
+        };
+        testRunner.start();
+        testRunner.join();
+
+        assertTrue(test1AssertionOutcome.get());
+        assertTrue(test2AssertionOutcome.get());
+    }
+    
+
+
+    /**
+     * Check that all threads spawned by application code gets an access to the 
+     * same mock
+     */
+    @Test
+    public void shouldInheritMocksWhenCodeThatIsBeingSpawnedByTestSpawnsANewThreads() throws InterruptedException {
+
+        final AtomicBoolean inheritedValueAssertionOutcome = new AtomicBoolean(false);
+        Thread testRunner = new Thread() {
+            @Override
+            public void run() {
+                try {
+                    when(interfaceToBeMocked.getValue()).thenReturn(11);
+
+                    // we simulate that tested code actually spawned a new
+                    // thread
+                    Thread inheritingThread = new Thread() {
+                        @Override
+                        public void run() {
+                            // the simulating code is executing mocks' recorded
+                            // codetry {
+                            assertAndSetOutcomeVariable(beanAutowiringMock.getValue(), 11, inheritedValueAssertionOutcome);
+                        }
+                    };
+
+                    inheritingThread.start();
+                    inheritingThread.join();
+                    
+                } catch (InterruptedException e) {
+                    inheritedValueAssertionOutcome.set(false);
+                }
+            }
+
+        };
+
+        testRunner.start();
+        testRunner.join();
+
+        assertTrue(inheritedValueAssertionOutcome.get());
+    }
+
+    private void assertAndSetOutcomeVariable(Integer value, Integer expectedValue, final AtomicBoolean outcomeVariable) {
+        assertEquals(value, Integer.valueOf(expectedValue));
+        outcomeVariable.set(value.equals(expectedValue));
+    }
+}

springockito-annotations/src/test/java/org/kubek2k/mockito/spring/SomeFancyClass.java

+package org.kubek2k.mockito.spring;
+
+public class SomeFancyClass {
+
+}

springockito-annotations/src/test/java/org/kubek2k/mockito/spring/testbeans/BeanAutowiringMock.java

+package org.kubek2k.mockito.spring.testbeans;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class BeanAutowiringMock {
+
+    private final InterfaceToBeMocked interfaceToBeMocked;
+
+    @Autowired
+    public BeanAutowiringMock(InterfaceToBeMocked interfaceToBeMocked) {
+        this.interfaceToBeMocked = interfaceToBeMocked;
+    }
+
+    public InterfaceToBeMocked getInterfaceToBeMocked() {
+        return interfaceToBeMocked;
+    }
+    
+    public Integer getValue() {
+        return interfaceToBeMocked.getValue();
+    }
+}

springockito-annotations/src/test/java/org/kubek2k/mockito/spring/testbeans/BeanToBeInjectedWithSpy.java

+package org.kubek2k.mockito.spring.testbeans;
+
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+@Component
+public class BeanToBeInjectedWithSpy {
+
+    private BeanToBeSpiedOrMockedAndStubbed beanToBeSpiedOrMockedAndStubbed;
+
+    public void callMethodWithoutArgumentsOnInjectedBeanTwice() {
+        beanToBeSpiedOrMockedAndStubbed.methodWithoutArgument();
+        beanToBeSpiedOrMockedAndStubbed.methodWithoutArgument();
+    }
+
+    @Resource
+    public void setBeanToBeSpiedOrMockedAndStubbed(BeanToBeSpiedOrMockedAndStubbed beanToBeSpiedOrMockedAndStubbed) {
+        this.beanToBeSpiedOrMockedAndStubbed = beanToBeSpiedOrMockedAndStubbed;