0

this simple mockito is failing I do not know why? I suspect set up is not complete? When I replace userService by userDAO in the test method it passes, why this happen?

public class UserServiceTest {

private static IUserService userService;
private static IUserDAO userDAO;

private User GENERIC_EMPLOYEE_1;


@BeforeClass
public static void setUpBeforeClass() throws Exception {
    userService = new UserService();
    userDAO = mock(IUserDAO.class);
    
}

@Before
public void setUp() throws Exception {
    
    GENERIC_EMPLOYEE_1 = new User(1, "genericEmployee1", "genericPassword", Role.EMPLOYEE);
   
  }

@Test
public void testGetByUsernamePassesWhenUsernameExists() {
    //Optional<User> u=userDAO.create(GENERIC_EMPLOYEE_1);
    //assertEquals(u.get().getUsername(),"genericEmployee1");
   when(userDAO.getByUsername(anyString())).thenReturn(Optional.of(GENERIC_EMPLOYEE_1));

    assertEquals(Optional.of(GENERIC_EMPLOYEE_1),
            userService.getByUsername(GENERIC_EMPLOYEE_1.getUsername()));

    verify(userDAO).getByUsername(GENERIC_EMPLOYEE_1.getUsername());
}

}

kobosh
  • 483
  • 2
  • 7
  • 23

1 Answers1

0

You aren't installing your mock userDAO into your real userService anywhere; your userDAO represents a single mocked instance, not a stand-in for every IUserDAO in your test.

In order for your tested userService to use your mocked userDAO, you may have to accept a userDAO (or any other IUserDAO instance) as a constructor argument in UserService. This kind of refactor would allow a system that uses UserService (e.g. production or your test) to manage or inject UserService's dependencies, rather than letting UserService create or control its own dependencies. This general technique is "Dependency Injection" or "Inversion of Control", but for something as small and immediate as this you don't need a framework or container that manages dependency injection for you. If you are unable to make a change like this, you can pursue one of several alternatives.

Where before you might have had:

public class UserService implements IUserService {
  private final IUserDao userDao;

  public UserService() {
    this.userDao = new UserDAO();
  }

  // ...
}

Instead, try this:

public class UserService implements IUserService {
  private final IUserDao userDao;

  public UserService() {
    this(new UserDAO());
  }

  /* package private for testing */
  UserService(IUserDao userDao) {
    this.userDao = userDao;
    // ...
  }

  // ...
}

This will then let you install your mock UserDAO into your real UserService:

@BeforeClass // see side note
public static void setUpBeforeClass() throws Exception {
    userDAO = mock(IUserDAO.class);   
    userService = new UserService(userDAO);
}

As a side note, it will be much easier to understand your tests if you instantiate your userService and userDAO in a @Before method instead of @BeforeClass, as this will prevent any test's setup from interfering in any other test. You may also look into MockitoJUnitRunner or MockitoRule for additional automation of your test setup.

Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251
  • thanks Jeff. I tried every combination of userService=mock(userDAO) /userService=mock(IUserService.classs) ...etc . please can you show how to mock userService. I learn by example rather than by concept – kobosh Jan 08 '22 at 15:16
  • @kobosh No, because you should not want to mock UserService when your test is trying to prove UserService's correctness. You should be setting up a real UserService with possibly-mocked dependencies like UserDAO so you can confirm UserService's behavior and interactions without a real database and without ensuring UserDAO is bug-free. – Jeff Bowman Jan 08 '22 at 16:34
  • thanks Jeff. userService=mock(userDAO) gives error: Description Resource Path Location Type The method mock(Class) in the type Mockito is not applicable for the arguments (IUserDAO) UserServiceTest.java. I don't know what/where to mockUserService. can you please show me – kobosh Jan 08 '22 at 18:30
  • @kobosh I've edited my example, but I am very concerned that you are still trying to mock UserService. You should not be trying to do that, and under no circumstance will mock(UserDAO.class) produce anything that resembles a UserService. – Jeff Bowman Jan 08 '22 at 19:01
  • Sorry I missed to see yoyr post in its integrity. let me try it and come to you. – kobosh Jan 08 '22 at 19:39