Spring injection: @MockBean @Repository is not injected

Viewed 8769

I'm trying to @MockBean a @Repository annotated class:

@Repository
public interface ApplicationDao extends MongoRepository<Application, String> {}

I'm injecting it into a @Service annotated class:

@Service
public class AuthorizationService {

    private ApplicationDao appsDao;
    private List<Application> allowedApplications;

    @Autowired
    public AuthorizationService(ApplicationDao appsDao) {
        this.appsDao = appsDao;   //<<MOCKED INJECTED BEAN>>
        this.fillApplications();
    }

    private void fillApplications() {
        this.appsDao.findAll()    //<<MOCKED method>>
           .forEach(entry -> {
            this.allowedApplications.put(entry.getName(), entry);
        });
    }

    public bool isAuthorized(Application application) {
        return this.allowedApplications
          .stream()
          .anyMatch(app -> app.getId().equals(application.getId()));
    }
}

My test mocking configuration looks like:

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

    private @Autowired AuthorizationService;
    private @MockBean ApplicationDao applicationDao;

    @Before
    public void setUp() {

        Application testApplication = new Application();
        testApplication.setName("test-application");
        List<Application> allowedApplications = new ArrayList<Application>();
        allowedApplications.add(testApplication);

        Mockito
            .when(this.applicationDao.findAll())
            .thenReturn(allowedApplications);
    }

    @Test
    public void test() {
        Application app = new Application();
        app.getId("test-application"); 
        assertTrue(this.authorizationService.isAuthorized(app));  //<<FAILS>>
    }
}

Nevertheless, my mocked object is not injected. I mean, when my AuthorizationService calls its injected ApplicationDao is returns an empty list instead of my mocked list.

I've tried to use @MockBean(name="applicationDao") as well. The behavior is the same.

I've also tried to configure my mocked bean using this code:

@TestConfiguration
public class RestTemplateTestConfiguration {

    @Bean("applicationDao")
    @Primary
    public static ApplicationDao mockApplicationDao() {
        ApplicationDao mock = Mockito.mock(ApplicationDao.class);

        Application testApplication = new Application();
        testApplication.setName("test-application");
        List<Application> allowedApplications = new ArrayList<Application>();
        allowedApplications.add(testApplication);

        Mockito
            .when(mock.findAll())
            .thenReturn(allowedApplications);

        return mock;
    }
}

However, it doesn't works right.

Application class is:

public class Application {
    private String id;

    //setters & getters
}

Any ideas?

2 Answers

First things first - the type of test. Answer: Unit test.

You are starting Spring context that manages a lifecycle of AuthorizationService and then you are trying to inject mock. What really happens is that Spring IoC container is injecting a real ApplicationDao (the one managed by Spring IoC container) into the AuthorizationService.

Solution:

Manage lifecyle of AuthorizationService by your test runner (like MockitoJUnitRunner and inject ApplicationDao mock into it):

@RunWith(MockitoJUnitRunner.class)
public class GroupReferencesTest {

    private @InjectMocks AuthorizationService authorizationService;
    private @Mock ApplicationDao applicationDao;

    @Before
    public void setUp() {

        Application testApplication = new Application();
        testApplication.setName("test-application");
        List<Application> allowedApplications = new ArrayList<Application>();
        allowedApplications.add(testApplication);

        Mockito
            .when(this.applicationDao.findAll())
            .thenReturn(allowedApplications);
    }

    @Test
    public void test() {
        Application app = new Application();
        app.getId("test-application"); 
        assertTrue(this.authorizationService.isAuthorized(app));
    }
}

Working example

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {AuthorizationService.class})
public class GroupReferencesTest {

    @Autowired
    private AuthorizationService;

    @MockBean
    private ApplicationDao applicationDao;

    @Test
    public void test() {
        //given
        Mockito.when(applicationDao.findAll()).thenReturn(emptyList());

        //when & then
        assertTrue(authorizationService.isAuthorized(app));
    }
}
Related