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.

  1. 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 throwing NullPointerException in the Controller because the TestService is null. How should I fix that?

  2. How should I mock the repository layer when we are using MongoDB. when I try to Mock MongoTemplate, It is throwing an error saying MongoConvertor must not be null

  3. 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.