Injecting Mockito mocks into a Spring bean

后端 未结 22 1177
庸人自扰
庸人自扰 2020-11-22 09:44

I would like to inject a Mockito mock object into a Spring (3+) bean for the purposes of unit testing with JUnit. My bean dependencies are currently injected by using the

相关标签:
22条回答
  • 2020-11-22 10:12

    I have a very simple solution using Spring Java Config and Mockito:

    @Configuration
    public class TestConfig {
    
        @Mock BeanA beanA;
        @Mock BeanB beanB;
    
        public TestConfig() {
            MockitoAnnotations.initMocks(this); //This is a key
        }
    
        //You basically generate getters and add @Bean annotation everywhere
        @Bean
        public BeanA getBeanA() {
            return beanA;
        }
    
        @Bean
        public BeanB getBeanB() {
            return beanB;
        }
    }
    
    0 讨论(0)
  • 2020-11-22 10:12

    Given:

    @Service
    public class MyService {
        @Autowired
        private MyDAO myDAO;
    
        // etc
    }
    

    You can have the class that is being tested loaded via autowiring, mock the dependency with Mockito, and then use Spring's ReflectionTestUtils to inject the mock into the class being tested.

    @ContextConfiguration(classes = { MvcConfiguration.class })
    @RunWith(SpringJUnit4ClassRunner.class)
    public class MyServiceTest {
        @Autowired
        private MyService myService;
    
        private MyDAO myDAOMock;
    
        @Before
        public void before() {
            myDAOMock = Mockito.mock(MyDAO.class);
            ReflectionTestUtils.setField(myService, "myDAO", myDAOMock);
        }
    
        // etc
    }
    

    Please note that before Spring 4.3.1, this method won't work with services behind a proxy (annotated with @Transactional, or Cacheable, for example). This has been fixed by SPR-14050.

    For earlier versions, a solution is to unwrap the proxy, as described there: Transactional annotation avoids services being mocked (which is what ReflectionTestUtils.setField does by default now)

    0 讨论(0)
  • 2020-11-22 10:12

    Update: There are now better, cleaner solutions to this problem. Please consider the other answers first.

    I eventually found an answer to this by ronen on his blog. The problem I was having is due to the method Mockito.mock(Class c) declaring a return type of Object. Consequently Spring is unable to infer the bean type from the factory method return type.

    Ronen's solution is to create a FactoryBean implementation that returns mocks. The FactoryBean interface allows Spring to query the type of objects created by the factory bean.

    My mocked bean definition now looks like:

    <bean id="mockDaoFactory" name="dao" class="com.package.test.MocksFactory">
        <property name="type" value="com.package.Dao" />
    </bean>
    
    0 讨论(0)
  • 2020-11-22 10:14
    @InjectMocks
    private MyTestObject testObject;
    
    @Mock
    private MyDependentObject mockedObject;
    
    @Before
    public void setup() {
            MockitoAnnotations.initMocks(this);
    }
    

    This will inject any mocked objects into the test class. In this case it will inject mockedObject into the testObject. This was mentioned above but here is the code.

    0 讨论(0)
  • 2020-11-22 10:14

    Posting a few examples based on the above approaches

    With Spring:

    @ContextConfiguration(locations = { "classpath:context.xml" })
    @RunWith(SpringJUnit4ClassRunner.class)
    public class TestServiceTest {
        @InjectMocks
        private TestService testService;
        @Mock
        private TestService2 testService2;
    }
    

    Without Spring:

    @RunWith(MockitoJUnitRunner.class)
    public class TestServiceTest {
        @InjectMocks
        private TestService testService = new TestServiceImpl();
        @Mock
        private TestService2 testService2;
    }
    
    0 讨论(0)
  • 2020-11-22 10:15

    Below code works with autowiring - it is not the shortest version but useful when it should work only with standard spring/mockito jars.

    <bean id="dao" class="org.springframework.aop.framework.ProxyFactoryBean">
       <property name="target"> <bean class="org.mockito.Mockito" factory-method="mock"> <constructor-arg value="com.package.Dao" /> </bean> </property>
       <property name="proxyInterfaces"> <value>com.package.Dao</value> </property>
    </bean> 
    
    0 讨论(0)
提交回复
热议问题