Hot questions for Using Mockito in autowired
Question:
I have a class A which is using 3 differnt classes with autowiring
public class A () { @Autowired private B b; @Autowired private C c; @Autowired private D d; }
While testing them, i would like to have only 2 of the classes (B & C) as mocks and have class D to be Autowired as normal running, this code is not working for me:
@RunWith(MockitoJUnitRunner.class) public class aTest () { @InjectMocks private A a; @Mock private B b; @Mock private C c; @Autowired private D d; }
Is it even possible to do so?
Answer:
It should be something like
@RunWith(SpringJUnit4ClassRunner.class) public class aTest () { @Mock private B b; @Mock private C c; @Autowired @InjectMocks private A a; }
If you want D
to be Autowired
dont need to do anything in your Test
class. Your Autowired
A
should have correct instance of D
.
Also i think you need to use SpringJUnit4ClassRunner
for Autowiring
to work, with contextConfiguration
set correctly.
Because you are not using MockitoJunitRunner
you need to initialize your mocks
yourself using
MockitoAnnotations.initMocks(java.lang.Object testClass)
Question:
I've read plenty of articles about how to mock Spring's bean and their autowired fields. But there is nothing I could find about autowired lists of beans.
Concrete problem
I've a class called FormValidatorManager
. This class loop through several validators which implements IFormValidator
.
@Component public class FormValidatorManager implements IValidatorManager { @Autowired private List<IFormValidator> validators; @Override public final IFieldError validate(ColumnDTO columnToValidate, String sentValue) { String loweredColName = columnToValidate.getName().toLowerCase(); IFieldError errorField = new FieldError(loweredColName); for (IEsmFormValidator validator : validators) { List<String> errrorsFound = validator.validate(columnToValidate, sentValue); //les erreurs ne doivent pas ĂȘtre cumulĂ©es. if(CollectionUtils.isNotEmpty(errrorsFound)){ errorField.addErrors(errrorsFound); break; } } return errorField; } }
I would like to test this class. But I can't find a way to mock validators
property.
What I've tried
Since IFormValidators
are singleton, I tried to mock several instances of these beans hoping them to be reflected in FormValidatorManager.validators
but without success.
Then, I tried to create a list of IFormValidators
which was annotated as @Mock
. By initiating the List
manually, I was hoping initMocks()
to inject the created list. That was still without success.
Here is my last try:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"classpath:spring/test-validator-context.xml"}) public class FormValidatorManagerTest { @Mock private RegexValidator regexValidator; @Mock private FormNotNullValidator notNullValidator; @Mock private FormDataTypeValidator dataValidator; @InjectMocks private FormValidatorManager validatorManager; @Mock private List<IEsmFormValidator> validators = new ArrayList<IEsmFormValidator>(); @Mock private ColumnDTO columnDTO; @Before public void init() { validators.add(notNullValidator); validators.add(regexValidator); validators.add(dataValidator); MockitoAnnotations.initMocks(this); Mockito.when(columnDTO.getTitle()).thenReturn("Mock title"); Mockito.when(columnDTO.getName()).thenReturn("Mock name"); } @Test public void testNoErrorFound(){ mockValidator(notNullValidator, new ArrayList<String>()); mockValidator(regexValidator, new ArrayList<String>()); mockValidator(dataValidator, new ArrayList<String>()); IFieldError fieldErrors = validatorManager.validate(columnDTO, "Not null value"); Assert.assertEquals(0, fieldErrors.getErrors().size()); verifyNumberOfValidateCalls(regexValidator, Mockito.atMost(1)); verifyNumberOfValidateCalls(dataValidator, Mockito.atMost(1)); verifyNumberOfValidateCalls(notNullValidator, Mockito.atMost(1)); } private void mockValidator(IFormValidator validator, List<String> listToReturn){ Mockito.when(validator.validate(Mockito.any(ColumnDTO.class), Mockito.anyString())).thenReturn( listToReturn ); } private void verifyNumberOfValidateCalls(IFormValidator validator, VerificationMode verifMode){ Mockito.verify(validator, verifMode).validate(Mockito.any(ColumnDTO.class), Mockito.anyString()); } }
An NPE is thrown in IFormValidator.validate()
which I thougth would be mocked. The concrete implementation should not be called.
This leads to a really bad behavior since some of my tests on that class are false positives while others completly fail.
I'm trying to figure out how to mock an autowired list of beans while still having the possibility to mock specific implementations.
Do you have an idea start of solution ?
Regards
Answer:
I finally figured it out...
Sometimes, asking a question can give you a better approach to your problems :p
The problem is I was linking the validators to the list before they were mocked. The validators was then null and no reference could be updated when the MockitAnnotations.initMocks(this)
was called.
Moreover, to avoid iterator problems on List
, I had to use @Spy
instead of @Mock
.
Here is the final solution:
@Mock private EsmRegexValidator regexValidator; @Mock private EsmFormNotNullValidator notNullValidator; @Mock private EsmFormDataTypeValidator dataValidator; @InjectMocks private EsmFormValidatorManager validatorManager; @Spy private List<IEsmFormValidator> validators = new ArrayList<IEsmFormValidator>(); @Mock private ColumnDTO columnDTO; @Before public void init() { MockitoAnnotations.initMocks(this); validators.add(notNullValidator); validators.add(regexValidator); validators.add(dataValidator); Mockito.when(columnDTO.getTitle()).thenReturn("Mock title"); Mockito.when(columnDTO.getName()).thenReturn("Mock name"); }
Question:
I am expanding upon the basic Spring Boot examples, adding an "autowired" repository dependency to my controller. I would like to modify the unit tests to inject a Mockito mock for that dependency, but I am not sure how.
I was expecting that I could do something like this:
@RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = MockServletContext.class) @WebAppConfiguration public class ExampleControllerTest { private MockMvc mvc; @InjectMocks ExampleController exampleController; @Mock ExampleRepository mockExampleRepository; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mvc = MockMvcBuilders.standaloneSetup(new ExampleController()).build(); } @Test public void getExamples_initially_shouldReturnEmptyList() throws Exception { mvc.perform(MockMvcRequestBuilders.get("/example").accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(content().string(equalTo("[]"))); } }
but it doesn't inject the mock into the MockMvc
. Can anyone explain how to do this with @Autowired
dependencies, rather than constructor arguments?
Answer:
Please use @RunWith(MockitoJUnitRunner.class)
instead of @RunWith(SpringJUnit4ClassRunner.class)
and you have to use the ExampleController exampleController;
field with the injected mocks instead of creating a new one in line mvc = MockMvcBuilders.standaloneSetup(new ExampleController()).build();
Question:
I am trying to set up my class to be used in Junit
.
However when I try to do the below I get an error.
Current Test Class:
public class PersonServiceTest { @Autowired @InjectMocks PersonService personService; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); assertThat(PersonService, notNullValue()); } //tests
Error:
org.mockito.exceptions.base.MockitoException: Cannot instantiate @InjectMocks field named 'personService' You haven't provided the instance at field declaration so I tried to construct the instance. However the constructor or the initialization block threw an exception : null
How can I fix this?
Answer:
You are not mocking anything in your code. @InjectMocks sets a class where a mock will be injected.
Your code should look like this
public class PersonServiceTest { @InjectMocks PersonService personService; @Mock MockedClass myMock; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); Mockito.doReturn("Whatever you want returned").when(myMock).mockMethod; } @Test() public void testPerson() { assertThat(personService.method, "what you expect"); }
Question:
I have a service class that I need to unit test. The service has a upload method which in turn calls other services(autowired beans) that updates the database. I need to mock some of these services and some to execute as it is.
@Service public class UploadServiceImpl implements UploadService{ @Autowired private ServiceA serviceA; @Autowired private ServiceB serviceB; public void upload(){ serviceA.execute(); serviceB.execute(): //code... }
In the above example I need to mock ServiceA, but i would like ServiceB to run as is and perform it's function. My Junit test looks like this:
@RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes=Swagger2SpringBoot.class) public class UploadServiceTest { @Mock private ServiceA serviceA; @InjectMocks private UploadServiceImpl uploadService; @Before public void init() { MockitoAnnotations.initMocks(this); } @Test public void testUpload(){ uploadService.upload(); }
When I execute this I get NPE at serviceB.execute();
in UploadServiceImpl
.
What could be the problem?
Note: I am not specifying the behavior of the mocked object because I don't really care and also default behavior of mocked objects are to do nothing.
Thanks!
Answer:
Usually when unit testing you want to mock all external dependencies of a class. That way the unit test can remain independent and focused on the class under test.
Nevertheless, if you want to mix Spring autowiring with Mockito mocks, an easy solution is to annotate with both @InjectMocks
and @Autowired
:
@InjectMocks @Autowired private UploadServiceImpl uploadService;
The net effect of this is that first Spring will autowire the bean, then Mockito will immediately overwrite the mocked dependencies with the available mocks.
Question:
could you help me please, some code:
@ContextConfiguration(locations = { "/applicationContext.xml" }) @RunWith(SpringJUnit4ClassRunner.class) public class TestUnit2 { @Mock private MongoOperations mongoTemplate; @InjectMocks @Autowired private WorkcircleRepositoryMongoImpl workCircleRepository; @Autowired private WorkcircleServiceImpl workCircleServiceImpl; @Before public void setUp() { .... when(mongoTemplate.findOne(new Query(), Person.class)).thenReturn(expectedPerson); MockitoAnnotations.initMocks(this); } @Test public void test() { ... workCircleServiceImpl.find()... }
But test is failed: NP in "... workCircleServiceImpl.find()..." line,
in separate way @InjectMocks & @Autowired work, but together are not worked.
Answer:
Usually when you are unit testing, you shouldn't initialize Spring context. So remove Autowiring.
Usually when you do integration testing, you should use real dependencies. So remove mocking.
You are mixing integration and unit test here.
Question:
I am trying to add mock object in CourseServiceImpl's courseDao field but it is not working.
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration( locations = {"file:src/main/webapp/WEB-INF/config/servlet-config.xml"} ) @ActiveProfiles("test") public final class CourseServiceTest { @Mock private CourseDao courseDao; @Autowired private CourseService courseService; @Before public void setUp() { MockitoAnnotations.initMocks(this); } @Test public void testCourseServiceNotNull() { assertNotNull(courseService); assertNotNull(courseDao); ReflectionTestUtils.setField(courseService, "courseDao", courseDao, CourseDao.class); }
The reflection statement throws an error that field "courseDao" didn't found. But, when I create an object using new operator then it works fine.
ReflectionTestUtils.setField(new CourseServiceImpl(), "courseDao", courseDao, CourseDao.class);
servlet-config.xml
<mvc:annotation-driven /> <mvc:resources location="pdfs" mapping="/pdfs/**" /> <security:global-method-security pre-post-annotations="enabled" /> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/view/" p:suffix=".jsp" p:order="2" /> <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver" p:contentNegotiationManager-ref="contentNegId" p:defaultViews-ref="defaultViewList" p:order="1" /> <bean id="contentNegId" class="org.springframework.web.accept.ContentNegotiationManager"> <constructor-arg> <bean class="org.springframework.web.accept.PathExtensionContentNegotiationStrategy"> <constructor-arg> <map> <entry key="json" value="application/json" /> <entry key="xml" value="application/xml" /> </map> </constructor-arg> </bean> </constructor-arg> </bean> <util:list id="defaultViewList"> <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" /> <bean class="org.springframework.web.servlet.view.xml.MarshallingView"> <constructor-arg> <bean class="org.springframework.oxm.xstream.XStreamMarshaller" p:autodetectAnnotations="true" /> </constructor-arg> </bean> </util:list> <bean class="org.springframework.web.servlet.view.BeanNameViewResolver" p:order="0" /> <bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver" p:defaultLocale="en" /> <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource" p:basename="messages" /> <context:property-placeholder location="classpath:messages.properties" /> <import resource="/hibernate-config.xml" /> <import resource="/hibernate-config-test.xml" />
hibernate-config-test.xml
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost:3306/school-repo-test" p:username="user" p:password="password" /> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" p:dataSource-ref="myDataSource" p:hibernateProperties-ref="hibernateProps" p:annotatedClasses-ref="mapClasses"> </bean> <util:list id="mapClasses"> <value>org.school.model.Course</value> <value>org.school.model.Role</value> <value>org.school.model.Staff</value> <value>org.school.model.Student</value> <value>org.school.model.Subject</value> </util:list> <util:properties id="hibernateProps"> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> <prop key="hibernate.show_sql">true</prop> </util:properties> <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager" p:sessionFactory-ref="sessionFactory" />
Apart from profile name, rest is same for hibernate-config file.
CourseServiceImpl
@Service(value = "courseService") @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW) public class CourseServiceImpl implements CourseService { @Autowired private MessageSource messageSource; @Autowired private CourseDao courseDao; @Autowired private ApplicationContext context;
Please advise.
Answer:
Your CourseServiceImpl
class has @Transactional
annotation which means that bean instance wrapped with "Transactional"
proxy before it injected as dependency in CourseServiceTest
and all other beans in Spring context. Such proxy instance hides all the private
fields of original CourseServiceImpl
instance.
So you cannot access fields you want because injected courseService
instance is not the original CourseServiceImpl
class any more, it is dynamic cglib
or JDK
proxy class.
Question:
I want to test a class using Spring + JUnit + Mockito but I don't manage to make it work properly.
Let's say my class references a Service:
@Controller public class MyController { @Autowired private MyService service; @PostConstruct public void init() { service.whatever(); } public void doSomething() { service.create(); } }
And this Service references a Repository:
@Service public class MyService { @Autowired private MyRepository repository; public void whatever() {} public void create() { repository.save(); } }
When testing the MyController class, I want the service to be mocked. The problem is: even when the service is mocked, Spring tries to inject the repository in the mock.
Here is what I did. Test class:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = { MyControllerTestConfiguration.class }) public class MyControllerTest { @Autowired private MyController myController; @Test public void testDoSomething() { myController.doSomething(); } }
Configuration class:
@Configuration public class MyControllerTestConfiguration { @Bean public MyController myController() { return new MyController(); } @Bean public MyService myService() { return Mockito.mock(MyService.class); } }
And the error I get: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [test.test.MyRepository] found for dependency
I tried to initialize the mock using Mockito's @InjectMocks
annotation but this fails because the @PostConstruct
method is called before the mocks injection, generating a NullPointerException
.
And I cannot simply mock the repository because in real life that would make me mock A LOT of classes...
Can anyone help me on this?
Answer:
Use constructor instead of field injection. That makes testing a lot easier.
@Service public class MyService { private final MyRepository repository; @Autowired public MyService(MyRepository repository) { this.repository = repository; } public void whatever() {} public void create() { repository.save(); } }
-
@Controller public class MyController { private final MyService service; @Autowired public MyController(MyService service) { this.service = service; } @PostConstruct public void init() { service.whatever(); } public void doSomething() { service.create(); } }
This has several advantages:
- You don't need Spring in your tests. This allows you to do proper unit tests. It also makes the test incredibly fast (from seconds to milliseconds).
- You cannot accidentally create an instance of a class without its dependencies which would result in a
NullPointerException
. - As @NamshubWriter pointed out:
[The instance fields for the dependencies] can be final, so 1) they cannot be accidentally modified, and 2) any thread reading the field will read the same value.
Discard the @Configuration
class and write a test like this:
@RunWith(MockitoJUnitRunner.class) public class MyControllerTest { @Mock private MyRepository repository; @InjectMocks private MyService service; @Test public void testDoSomething() { MyController myController = new MyController(service); myController.doSomething(); } }
Question:
I want to replace an autowired class of a service in my spring boot app with a mocked implementation of that class that I created specifically for testing.
I chose to create this mocked implementation because the behaviour of this class is too complicated to mock using mockito as it requires multiple other mocks itself.
I am not able to work out how to inject this mocked implementation into the service.
Here is a minimal example of the situation:
@Service public class ServiceIWantToTestImpl implements ServiceIWantToTest{ @Autowired ComplicatedDependency complicatedDependency; @Override public void methodUsingDependency(){ String string = complicatedDependency.doSomething(); System.out.println(string); } } public class MockComplicatedDependency implements ComplicatedDepencency{ public MockComplicatedDependency(...){ // Inject other mocked objects into this mock } public String doSomthing(){ // This would be a mocked version of this function for testing return "test"; } } @RunWith(MockitoJUnitRunner.class) public class TestingTheService(){ @InjectMock private static ServiceIWantToTest serviceIWantToTest = new ServiceIWantToTestImpl(); @Mock ComplicatedDependency mockComplicatedDependency; @BeforeClass public static void init(){ mockComplicatedDependency = new MockComplicatedDependency(...); } @Test public void testAttempt(){ serviceIWantToTest.methodUsingDependency(); // This method calls complicatedDependency.doSomething() which does not run the mocked version in MockComplicatedDependency which I wanted to inject, and would always return null instead of the "test" string I put in this example. } }
Answer:
Do you have to use Mockito annotations to setup dependencies for the class under test?
If that is not the main constraint why not just do the plain simple setup and introduce a constructor or a setter in ServiceIWantToTestImpl
class for the ComplicatedDependency
field and set the dependency in your test setup directly to whatever impl of ComplicatedDependency you like e.g.:
@Service public class ServiceIWantToTestImpl implements ServiceIWantToTest { @Autowired ComplicatedDependency complicatedDependency; public ServiceIWantToTestImpl() { } public ServiceIWantToTestImpl(ComplicatedDependency complicatedDependency) { this.complicatedDependency = complicatedDependency; } @Override public void methodUsingDependency(){ String string = complicatedDependency.doSomething(); System.out.println(string); } } public class TestingTheService { private static ServiceIWantToTestImpl serviceIWantToTest; @BeforeClass public static void init(){ serviceIWantToTest = new ServiceIWantToTestImpl(new MockComplicatedDependency()); } @Test public void testAttempt() { serviceIWantToTest.methodUsingDependency(); } }
That is one way.
To make it work with Mockito, You could to use @Spy instead of @Mock like this:
@RunWith(MockitoJUnitRunner.class) public class TestingTheService { @InjectMocks private static ServiceIWantToTestImpl serviceIWantToTest = new ServiceIWantToTestImpl(); @Spy private static ComplicatedDependency complicatedDependency = new MockComplicatedDependency(); @BeforeClass public static void init() { } @Test public void testAttempt() { serviceIWantToTest.methodUsingDependency(); } }
Though this is a bit of a hack. I strongly recommend that you read the JavaDoc of the @Spy annotation and make sure it's expected use is what you really need for your test.
Question:
I'd like to test a service class which has two other service classes like as below using Mockito
.
@Service public class GreetingService { private final Hello1Service hello1Service; private final Hello2Service hello2Service; @Autowired public GreetingService(Hello1Service hello1Service, Hello2Service hello2Service) { this.hello1Service = hello1Service; this.hello2Service = hello2Service; } public String greet(int i) { return hello1Service.hello(i) + " " + hello2Service.hello(i); } } @Service public class Hello1Service { public String hello(int i) { if (i == 0) { return "Hello1."; } return "Hello1 Hello1."; } } @Service public class Hello2Service { public String hello(int i) { if (i == 0) { return "Hello2."; } return "Hello2 Hello2."; } }
I know how to mock Hello1Service.class
and Hello2Service.class
with Mockito
like as below.
@RunWith(MockitoJUnitRunner.class) public class GreetingServiceTest { @InjectMocks private GreetingService greetingService; @Mock private Hello1Service hello1Service; @Mock private Hello2Service hello2Service; @Test public void test() { when(hello1Service.hello(anyInt())).thenReturn("Mock Hello1."); when(hello2Service.hello(anyInt())).thenReturn("Mock Hello2."); assertThat(greetingService.greet(0), is("Mock Hello1. Mock Hello2.")); } }
I'd like to mock Hello1Service.class
and inject Hello2Service.class
using @Autowired
like as below.
I tired to use @SpringBootTest
but it did not work.
Is there a better way?
@RunWith(MockitoJUnitRunner.class) public class GreetingServiceTest { @InjectMocks private GreetingService greetingService; @Mock private Hello1Service hello1Service; @Autowired private Hello2Service hello2Service; @Test public void test() { when(hello1Service.hello(anyInt())).thenReturn("Mock Hello1."); assertThat(greetingService.greet(0), is("Mock Hello1. Hello2.")); } }
Answer:
You want to inject dependency with some functionality to be formed then use @Spy
.
You don't to load Spring Container and use @Autowired
.
@Spy private Hello2Service hello2Service=new Hello2Service();
You can read more detail about Mock vs Spy ;
https://dzone.com/articles/mockito-mock-vs-spy-in-spring-boot-tests
Question:
I am trying to test a ClassA
which uses 2 services. One service needs to be autowired and one to be treated as mocked object instead. Unfortunately mocked object is
not injected
to my tested class. All fields are behaving like I would only use spring autowiring feauture to set it up. Tested ClassA is inheriting from other abstract class also. If no autowiring is used, mocked object is passed succesfully. Unfortunately I can't mocked ServiceDao, thats why I am trying to combine @InjectMocks
and @Autowiring
annotation.
Class A.
public ClassA extends AbstractClassA<ClassOne, ClassTwo>{ @Autowired protected ServiceOne serviceOne; //this services needs to be mocked @Override protected List<ClassTwo> testedMethod(){ return serviceOne.getList(); //here method is not returning mocked objects } //as it supposed to do. ........ }
AbstractClass
public class AbstractClassA<T1 extends InterfaceOne, T2 extends InterfaceTwo){ @Autowired protected ServiceDAO serviceDAO; //this services needs to be autowired protected abstract List<T2> testedMethod(); }
TestClass.
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath*:testApplicationContext.xml"}) public class Test { @Mock private ServiceOne serviceOne; //this mock object and it's return //objects are set properly @Autowired @InjectMocks private ClassA classA; //all fields are autowired, including the services that should be mocked @Before public void setData(){ Mockito.Annotations.initMocks(this); List<ClassTwo> result = Arrays.asList(new ClassA()); when(serviceOne.testedMethod().thenReturn(result); //here when i invoke mocked object it is returning correct list. } }
Answer:
In this case it's probably best to mock the injected bean via your Spring test context configuration. If you are not able to do that easily, you can using Springs ReflectionTestUtils class to mock individual objects in your service.
In your test configuration XML file you can define a mocked bean:
<bean id="serviceOne" class="org.mockito.Mockito" factory-method="mock"/> <constructor-arg value="com.package.ServiceOne"/> </bean>
In Java side:
@Bean public ServiceOne serviceOne() { return mock(ServiceOne.class); }
In your test case you can @Autowire ServiceOne serviceOne
and use that as your mock object:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath*:testApplicationContext.xml"}) public class Test { @Autowired private ServiceOne serviceOne; @Autowired private ClassA classA; @Before public void setData(){ Mockito.Annotations.initMocks(this); List<ClassTwo> result = Arrays.asList(new ClassA()); when(serviceOne.testedMethod()).thenReturn(result); } }
Question:
I am writing a series of test cases for a class with a few methods like:
public ServiceResponse getListOfGroups() { ServiceResponse serviceResponse = new ServiceResponse(); try{ Slf4JStopWatch sw = new Slf4JStopWatch("GetListOfGroups", log, DEBUG_LEVEL); List<Group> Groups = Arrays.asList(restTemplate.getForObject(getGroupServiceURL(), Group[].class)); sw.stop(); serviceResponse.setData(Groups); } catch(ServiceException ex) { serviceResponse.setErrorObject(ex.getErrorObject()); } return serviceResponse; }
The problem I am having is the fact that the restTemplate
is @autowired
from the actual implementation of the class (and therefore returning null when called in the unit test perspective). How would I go about writing a proper test case for these methods?
Here is what I have tried so far:
@Test public void testGetListOfGroups() { //TODO ServiceResponse resp = new ServiceResponse(); Mockito.when(uwsci.getListOfGroups()).thenReturn(resp); //uwsci is my mocked object assertTrue(uwsci.getListOfGroups() == resp); }
I feel that this defeats the point of unit testing as it is just returning what I told it to and not really doing anything else.
Answer:
Since you chose field injection, the only way to inject a mock dependency in your object is to use reflection. If you had used constructor injection instead, it would be as easy as
RestTemplate mockRestTemplate = mock(RestTemplate.class); ClassUnderTest c = new ClassUnderTest(mockRestTemplate);
Fortunately, Mockito makes that possible using its annotations support:
@Mock private RestTemplate mockRestTemplate; @InjectMocks private ClassUnderTest classUnderTest; @Before public void prepare() { MockitoAnnotations.initMocks(this); }
Question:
I wanted to do integration testing of my API.
@RestController @RequestMapping("/api/v1") public class TestController { @Autowired TestService testService; @RequestMapping("/welcome") public String welcomeMessage(@RequestParam("name") String name) { return testService.welcomeMessage(name); } }
Below are the service interface and its implementation:
public interface TestService { public String welcomeMessage(String name); } public class TestServiceImpl implements TestService{ @Autowired TestRepository repo; @Override public String welcomeMessage(String name) { repo.save(new StringEntity(name)); return "Hello "+name; } }
Below is the Test Case:
@RunWith(SpringRunner.class) @SpringBootTest @AutoConfigureMockMvc public class MockitoTestingApplicationTests { @Autowired MockMvc mvc; @MockBean TestService testService; @MockBean TestController testController; @Test public void contextLoads() throws Exception { Mockito.when(testController.welcomeMessage(ArgumentMatchers.anyString())).thenCallRealMethod(); Mockito.when(testService.welcomeMessage(ArgumentMatchers.anyString())).thenCallRealMethod(); mvc.perform(get("/api/v1/welcome").param("name", "dude")).andExpect(status().isOk()); } }
I have a few questions.
when I'm executing the above code it is throwing an error saying cannot call real method on abstract methods. And When I'm mocking the
TestServiceImpl
, It is throwingNullPointerException
in the Controller because theTestService
is null. How should I fix that?How should I mock the repository layer when we are using MongoDB. when I try to Mock
MongoTemplate
, It is throwing an error sayingMongoConvertor must not be null
Is this the right way to write test cases. can we have code coverage without using
thenCallRealMethod()
?
Please suggest me how to proceed. Thanks in advance.
Answer:
Make sure you have an implementation of the service i.e. TestServiceImpl
annotated with @Service
(or @Component
if it is not strictly a service) and use spying instead of mocking:
@SpyBean TestService testService;
Spying by default call real methods so you have to mock these that implementation you do not want to call.
Regarding repositories, you should mock the components annotated with @Repository
, not the actual SessionFactory
/ Template
etc. that are used within.
Question:
I have a service with an attribute like this:
@Autowired @Qualifier("test") private String test;
This attribute come from context xml file.
I become nothing in unit test, probably that a correct behavior in unit test. But can I mock this attribute to become a value?
for example:
when(test).thenReturn("a string");
Thanks Regards
Answer:
Based on your comment making the field public is an option. You can just set it afterwards:
myMock = Mock(MyClass) myMock.test = "foobar"
Besides that you could add a setter, leaving the field private. Or you could try @InjectMocks
or Spring's ReflectionTestUtils
, both from the accepted answer here.
Question:
I'm new to Spring-Boot, TestNG and MockMVC, when i try to write TestNG test case it gives Null for below:
@Autowired private WebApplicationContext webApplicationContext;
and also it gives null for
@BeforeTest public void start() { mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); }
Also, based on previous post from stackoverflow by moving
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
to @Test also the problem not resolved.
Below my code snippet
@Autowired private WebApplicationContext webApplicationContext; private MockMvc mockMvc; @BeforeTest public void setup() { mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); } @Test public void testEmployee() throws Exception { mockMvc.perform(get("/employee")).andExpect(status().isOk()) .andExpect(content().contentType("application/json;charset=UTF-8")) .andExpect(jsonPath("$.name").value("emp1")).andExpect(jsonPath("$.designation").value("manager")) .andExpect(jsonPath("$.empId").value("1")).andExpect(jsonPath("$.salary").value(3000)); }
Any link or working sample shared will be great help.
thanks
Answer:
If you want to autowire WebApplicationContext
, your test class should be annotated with @ContextConfiguration
and @WebAppConfiguration
.
You can find an example-ish here (Spring Framework's official repository).
Question:
Naively I thought I could set a mockito to un already initialized spring bean. When I do that somewhere along the way the bean is getting back the original spring injected value.
Is there no other way than injecting the mock thru xml or java spring config?
Thanks
Answer:
I assume you are talking about integration tests that you run e.g. with '@RunWith(SpringJUnit4ClassRunner.class)'. In unit tests you would not usually deal with Spring - this is the advantage of Spring and DI.
I usually override the production configuration with test configuration using the following:
- To override @Autowired/@Injected bean, mark your beans in the test configurations as @Primary
- To override beans injection by name, use aliases in your test configuration (see an example below)
Your production config:
@Configuration class ProdConfig { @Bean Abc abc() { return new AbcImpl(); } @Bean Xyz xyz() { return new XyzImpl(); } } class SomeBean { @Inject Abc abc; @Resource(name="xyz") Xyz xys; }
Your test config:
@Configuration @Import(ProdConfig.class) class TestConfig { @Primary @Bean(name={"abcOverride", "abc"}) Abc abc() { return Mockito.mock(Abc.class); } @Primary @Bean(name={"xyzOverride", "xyz"}) Xyz xyz() { return Mockito.mock(Xyz.class); } }
And then in your test:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = TestConfig.class) @TestPropertySource(properties = {"some.prop=true"}) //you can override properties as well class MyTest {...}
One more thing: you might need to explicitly exclude your TestConfig classes to avoid interfering with other integration tests:
@Configuration @ComponentScan(basePackages={"com.your.code"}, excludeFilters = {@ComponentScan.Filter(pattern = ".*TestConfig.*")}) class ProdConfig {...}
Question:
I have a user defined annotation class as follows.
@Target({ TYPE, METHOD, PARAMETER, FIELD }) @Retention(RUNTIME) @Qualifier public @interface Message { Dest value(); public static enum Target { DEFAULT, TEST } }
I use this annotation in the following way.
@Component public class ProcessorBean implements Processor { @Autowired @Message(Message.Target.DEFAULT) Producer<Object, Object> messageProducer; @Autowired MessageConfig messageConfig;
Not sure, how to create a bean of ProcessorBean and inject Producer.
@Bean(name="DEFAULT") public Producer<Object, Object> producer() { return mock(Producer.class); }
I tried the above one and it is throwing dependency error.
Thanks
Answer:
I found the solution myself. Hope, this will be helpful for others.
@Message(Message.Target.DEFAULT) @Bean public Producer<Object, Object> producer() { return mock(Producer.class); }
Question:
The class that I want to test is called UserService
with sendEmail
method, which sends an email to user.
To accomplish this task it depends on EmailService
. Now when writing a testcase to test this - should I create UserService userService = new UserService()
and mock Email service OR create context file define UserService
bean there and @Autowired UserService
in my test class and mock EmailService
?
What is the difference between both approaches and when should i use one over the other? Which of these is a real object?
Answer:
If your class is meant to be a bean, and for example you also have the expectation to get dependencies injected, you should not create instances with the new operator. Please check inject-doesnt-work-with-new-operator answer
You can create a TestConfig.class
and mock the dependencies of the UserService
(using a mock framework that you like - I prefer mockito). In this TestConfig, you create your bean:
@Configuration public static class TestConfig { @Bean private EmailService emailService() { return Mockito.mock(EmailService.class); } //Assuming that you have constructor injection. @Bean public UserService userService() { return new UserService(emailService()); } }
Question:
I have begun to use ScalaTest to test my Java code and I like it (I've read the "Testing in Scala" book).
Recently I've been trying to test some java Spring code that contain fields which are marked private
and @Autowired
. There are no setter methods for these fields.
I realise that I could easily test them using JUnit + Mockito using the annotations @InjectMocks
and @Mock
, however, I would like to test them using ScalaTest and a mocking framework (such as Mockito or ScalaMock).
My question: Can Scalatest + Mockito be used to mock out private fields or do these frameworks require that my java classes have a public
setter method defined for my private
+ @Autowired
fields?
Answer:
You can do it with InjectMocks. Here's a working example using ScalaTest and Mockito to test a class containing @Autowired members:
import org.mockito.{MockitoAnnotations, InjectMocks, Mock} import org.scalatest.{FunSpec, BeforeAndAfter} import org.scalatest.Matchers._ import org.mockito.Mockito._ import org.springframework.beans.factory.annotation.Autowired class InjectMocksSpec extends FunSpec with BeforeAndAfter { @Mock var paramMock: MockedClass = null @InjectMocks var testClass = new TestClass() describe("InjectMocks") { it("should inject mock for Autowired field") { MockitoAnnotations.initMocks(this) when(paramMock.get).thenReturn("bar") testClass.test should be("bar") verify(paramMock, times(1)).get } } } class MockedClass { def get: String = { "foo" } } class TestClass { @Autowired var param: MockedClass = null def test: String = { param.get } }
Question:
I have problem while writing test for getStudentInfo()
, I want to make a real call to getaddress()
instead of using expects
.
public class Student { @Autowired private Address address; public String getStudentInfo(String name) { string address = address.getAddress(name); return address; } }
Test:
public class StudentTest { @InjectMock private Student student; @Test public void testStudentInfo() { String name = student.getStudentInfo("name"); } }
When use above approach, Address object is not creating. I don't want to use the new
keyword to create new Address object.
Answer:
First, it is wrong to have @Autowire
there. Just add a constructor or setter method.
After that, you need to mock (spy) that stuff. Try this:
public class StudentTest { @InjectMock private Student student; // this mock will be injected into student // but the real method will be called (unless a method was stubbed explicitly). @Spy private Address address; @Test public void testStudentInfo(){ String name = student.getStudentInfo("name"); } }
The stuff you need in general is called partial mock. See the link at the top.