7

I have restful services and I want to unit test them without connecting to database, therefore I have written this piece of code:

@Before
public void setup() throws Exception {
    this.mockMvc = webAppContextSetup(webApplicationContext).build();

    adminDao = mock(AdminDaoImpl.class);
    adminService = new AdminServiceImpl(adminDao);
}

@Test
public void getUserList_test() throws Exception {
    User user = getTestUser();
    List<User> expected = spy(Lists.newArrayList(user));

    when(adminDao.selectUserList()).thenReturn(expected);


    mockMvc.perform(get("/admin/user"))
        .andExpect(status().isOk())
        .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
        .andExpect(jsonPath("$", hasSize(1)))
        ;           
}

The service gets called but my problem is this line of code

when(adminDao.selectUserList()).thenReturn(expected);

is not working, I mean it really calls the adminDao.select method and therefore gets the result from database. which I don't want. Do you have any idea how can I mock the method call?

Shilan
  • 813
  • 1
  • 11
  • 17
  • 2
    They work perfectly fine together, but you are mocking classes outside of the context, how should the context know about those mocks? – M. Deinum Apr 28 '16 at 11:23
  • @M.Deinum you are right, i know that i get webApplicationContext, but actually I cannot find a way to mock them inside the mockMVC context. How can i fix it? – Shilan Apr 28 '16 at 11:29
  • Create a configuration class which overrides the actual beans with mocks. Inject the mocks in our test class to record the behavior you want. – M. Deinum Apr 28 '16 at 11:32
  • So you mean that I need to create a class like @Configuration public class TestContext {} and then inject it like this @ContextConfiguration(classes = {TestContext.class, WebAppConfig.class}) Sorry just want to make sure i am getting your real meaning. – Shilan Apr 28 '16 at 11:39
  • maybe this answer will solve your problem: http://stackoverflow.com/a/16207069/887692 – Rich Apr 29 '16 at 08:46

2 Answers2

7

Thanks to @M. Deinum, I fixed my problem, I added a TestContext configuration file:

@Configuration
public class TestContext {

@Bean
public AdminDaoImpl adminDao() {
    return Mockito.mock(AdminDaoImpl.class);
}

@Bean
public AdminServiceImpl adminService() {
    return new AdminServiceImpl(adminDao());
}       
}

and then in my test class I annotated the class with

@ContextConfiguration(classes = {TestContext.class})

worth to mention in setUp of the test class I need to reset the mockedClass to prevent leakage:

@Before
public void setup() throws Exception {
    Mockito.reset(adminDaoMock);

    mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
Shilan
  • 813
  • 1
  • 11
  • 17
  • can you please post your full Test class after these changes? – KayKay Nov 08 '19 at 11:53
  • This is my issue and I am a bit stuck with this https://stackoverflow.com/questions/58766781/mokcito-not-mocking-the-dao-layer – KayKay Nov 08 '19 at 14:30
1

Instead of creating a separate TestContext class use @MockBean annotation for the same.

 @MockBean
 AdminDao adminDao;

And then use it as per your need.

 @Test
public void getUserList_test() throws Exception {
   User user = getTestUser();
   List<User> expected = spy(Lists.newArrayList(user));

   when(adminDao.selectUserList()).thenReturn(expected);


   mockMvc.perform(get("/admin/user"))
    .andExpect(status().isOk())
    .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
    .andExpect(jsonPath("$", hasSize(1)))
    ;           
}
Deepak Goel
  • 5,624
  • 6
  • 39
  • 53