Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 524 Vote(s) - 3.42 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Injecting Mockito mocks into a Spring bean

#11
As of Spring 3.2, this is no longer an issue. Spring now supports Autowiring of the results of generic factory methods. See the section entitled "Generic Factory Methods" in this blog post:

[To see links please register here]

.

The key point is:


> In Spring 3.2, generic return types for factory methods are now
> properly inferred, and autowiring by type for mocks should work as
> expected. As a result, custom work-arounds such as a
> MockitoFactoryBean, EasyMockFactoryBean, or Springockito are likely no
> longer necessary.

Which means this should work out of the box:

<bean id="dao" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.package.Dao" />
</bean>
Reply

#12
**Update** - new answer here:

[To see links please register here]

. This answer only applies to those on Spring versions before 3.2.

I've looked for a while for a more definitive solution to this. This blog post seems to cover all my needs and doesn't rely on ordering of bean declarations. All credit to Mattias Severson.

[To see links please register here]


Basically, implement a FactoryBean

package com.jayway.springmock;

import org.mockito.Mockito;
import org.springframework.beans.factory.FactoryBean;

/**
* A {@link FactoryBean} for creating mocked beans based on Mockito so that they
* can be {@link @Autowired} into Spring test configurations.
*
* @author Mattias Severson, Jayway
*
* @see FactoryBean
* @see org.mockito.Mockito
*/
public class MockitoFactoryBean<T> implements FactoryBean<T> {

private Class<T> classToBeMocked;

/**
* Creates a Mockito mock instance of the provided class.
* @param classToBeMocked The class to be mocked.
*/
public MockitoFactoryBean(Class<T> classToBeMocked) {
this.classToBeMocked = classToBeMocked;
}

@Override
public T getObject() throws Exception {
return Mockito.mock(classToBeMocked);
}

@Override
public Class<?> getObjectType() {
return classToBeMocked;
}

@Override
public boolean isSingleton() {
return true;
}
}

Next update your spring config with the following:

<beans...>
<context:component-scan base-package="com.jayway.example"/>

<bean id="someDependencyMock" class="com.jayway.springmock.MockitoFactoryBean">
<constructor-arg name="classToBeMocked" value="com.jayway.example.SomeDependency" />
</bean>
</beans>
Reply

#13
I can do the following using Mockito:

<bean id="stateMachine" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.abcd.StateMachine"/>
</bean>
Reply

#14
I use a combination of the approach used in answer by Markus T and a simple helper implementation of `ImportBeanDefinitionRegistrar` that looks for a custom annotation (`@MockedBeans`) in which one can specify which classes are to be mocked. I believe that this approach results in a concise unit test with some of the boilerplate code related to mocking removed.

Here's how a sample unit test looks with that approach:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class)
public class ExampleServiceIntegrationTest {

//our service under test, with mocked dependencies injected
@Autowired
ExampleService exampleService;

//we can autowire mocked beans if we need to used them in tests
@Autowired
DependencyBeanA dependencyBeanA;

@Test
public void testSomeMethod() {
...
exampleService.someMethod();
...
verify(dependencyBeanA, times(1)).someDependencyMethod();
}

/**
* Inner class configuration object for this test. Spring will read it thanks to
* @ContextConfiguration(loader=AnnotationConfigContextLoader.class) annotation on the test class.
*/
@Configuration
@Import(TestAppConfig.class) //TestAppConfig may contain some common integration testing configuration
@MockedBeans({DependencyBeanA.class, DependencyBeanB.class, AnotherDependency.class}) //Beans to be mocked
static class ContextConfiguration {

@Bean
public ExampleService exampleService() {
return new ExampleService(); //our service under test
}
}
}

To make this happen you need to define two simple helper classes - custom annotation (`@MockedBeans`) and a custom
`ImportBeanDefinitionRegistrar` implementation. `@MockedBeans` annotation definition needs to be annotated with `@Import(CustomImportBeanDefinitionRegistrar.class)` and the `ImportBeanDefinitionRgistrar` needs to add mocked beans definitions to the configuration in it's `registerBeanDefinitions` method.

If you like the approach you can find sample [implementations][2] on my [blogpost][1].

[1]:

[To see links please register here]

[2]:

[To see links please register here]


Reply

#15
I developed a solution based on the proposal of Kresimir Nesek. I added a new annotation *@EnableMockedBean* in order to make the code a bit cleaner and modular.

@EnableMockedBean
@SpringBootApplication
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes=MockedBeanTest.class)
public class MockedBeanTest {

@MockedBean
private HelloWorldService helloWorldService;

@Autowired
private MiddleComponent middleComponent;

@Test
public void helloWorldIsCalledOnlyOnce() {

middleComponent.getHelloMessage();

// THEN HelloWorldService is called only once
verify(helloWorldService, times(1)).getHelloMessage();
}

}

I have written a [post](

[To see links please register here]

) explaining it.
Reply

#16
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>
Reply

#17
I would suggest to migrate your project to Spring Boot 1.4. After that you can use new annotation [`@MockBean`][1] to fake your `com.package.Dao`


[1]:

[To see links please register here]

Reply

#18
If you're using Spring Boot 1.4, it has an awesome way of doing this. Just use new brand `@SpringBootTest` on your class and `@MockBean` on the field and Spring Boot will create a mock of this type and it will inject it into the context (instead of injecting the original one):

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {

@MockBean
private RemoteService remoteService;

@Autowired
private Reverser reverser;

@Test
public void exampleTest() {
// RemoteService has been injected into the reverser bean
given(this.remoteService.someCall()).willReturn("mock");
String reverse = reverser.reverseSomeCall();
assertThat(reverse).isEqualTo("kcom");
}

}


On the other hand, if you're not using Spring Boot or are you using a previous version, you'll have to do a bit more work:

Create a `@Configuration` bean that injects your mocks into Spring context:

@Configuration
@Profile("useMocks")
public class MockConfigurer {

@Bean
@Primary
public MyBean myBeanSpy() {
return mock(MyBean.class);
}
}

Using `@Primary` annotation you're telling spring that this bean has priority if no qualifier are specified.

Make sure you annotate the class with `@Profile("useMocks")` in order to control which classes will use the mock and which ones will use the real bean.

Finally, in your test, activate `userMocks` profile:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {Application.class})
@WebIntegrationTest
@ActiveProfiles(profiles={"useMocks"})
public class YourIntegrationTestIT {

@Inject
private MyBean myBean; //It will be the mock!


@Test
public void test() {
....
}
}

If you don't want to use the mock but the real bean, just don't activate `useMocks` profile:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {Application.class})
@WebIntegrationTest
public class AnotherIntegrationTestIT {

@Inject
private MyBean myBean; //It will be the real implementation!


@Test
public void test() {
....
}
}

Reply

#19
@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.
Reply

#20
If you're using **spring >= 3.0**, try using Springs `@Configuration` annotation to define part of the application context

@Configuration
@ImportResource("com/blah/blurk/rest-of-config.xml")
public class DaoTestConfiguration {

@Bean
public ApplicationService applicationService() {
return mock(ApplicationService.class);
}

}

If you don't want to use the @ImportResource, it can be done the other way around too:

<beans>
<!-- rest of your config -->

<!-- the container recognize this as a Configuration and adds it's beans
to the container -->
<bean class="com.package.DaoTestConfiguration"/>
</beans>

For more information, have a look at spring-framework-reference : [Java-based container configuration][1]



[1]:

[To see links please register here]

Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through