Nate
Nate

Reputation: 67

How @Autowire works in spring-boot unit test?

I was wondering how @autowire works here?

I am tring to practise how to use mock to do unit test in Spring.

Here is the code for my simple UserService

@Service
public class UserService {

    @Autowired
    UserRepository userRepository;

    public User findByName(String name) {

        return userRepository.findByName(name);
    }
}

Here is the code for my unit test.

package com.geotab.dna.springtestdemo.services;

import com.geotab.dna.springtestdemo.entities.User;
import com.geotab.dna.springtestdemo.repositories.UserRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
public class UserServiceTest {

    @TestConfiguration
    static class UserServiceImplContextConfiguration {

        @Bean
        public UserService userService() {
            UserService userService = new UserService();
            return userService;
        }
    }

    @Autowired
    private UserService userService;

    @MockBean
    private UserRepository userRepository;

    @Test
    public void whenFindByName_thenReturnUser() {

        //given
        String name = "alex";
        User user = new User(name);
        Mockito.when(userRepository.findByName(name)).thenReturn(user);

        //when
        User found = userService.findByName("alex");

        //then
        assert (user.getName().equals(found.getName()));
    }
}

I got the above code from a blog, it works. But I am confused that why UserRepository could be injected into UserService? Because at the very beginning I am thinking that UserService.UserRepository will be null.

Upvotes: 1

Views: 1071

Answers (1)

pvpkiran
pvpkiran

Reputation: 27078

Just look at different parts of the program what you have

  1. @RunWith(SpringRunner.class) you are using a runner class provided by Spring
  2. @Autowire which makes spring search for the class in its application context when it encoutners this statement.

Now coming to the point how does userRepository object gets injected into userService. This is because of @MockBean. From the documentation it says

Annotation that can be used to add mocks to a Spring ApplicationContext. Can be used as a class level annotation or on fields in either @Configuration classes, or test classes that are @RunWith the SpringRunner.

This means when spring encounters @MockBean, it adds that bean to application context. Hence when it encounters @Autowired on userRepository inside userService, it injects the mock instance it has.
This annotation was introduced in a few releases back. Before that we had to declare a mock using @Mock and use @InjectMocks or using construction injection.

Look at this question for more on the differente between @Mock and @MockBean

Upvotes: 1

Related Questions