常规单元测试通过但 Mockito 全部失败
Regular unit tests pass but Mockito all fail
这个简单的 mockito 失败了,我不知道为什么?我怀疑设置不完整?
当我在它通过的测试方法中用 userDAO 替换 userService 时,为什么会这样?
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());
}
}
您没有在任何地方将您的模拟 userDAO
安装到您的真实 userService
中;您的 userDAO
表示单个模拟实例,而不是测试中每个 IUserDAO 的替代。
为了让您测试的 userService
使用模拟的 userDAO
,您可能必须接受 userDAO
(或任何其他 IUserDAO 实例)作为 UserService 中的构造函数参数。这种重构将允许使用 UserService(例如生产或测试)的系统来管理或 inject UserService 的 dependencies,而不是让 UserService 创建或者控制它自己的依赖。这种通用技术是“依赖注入”或“控制反转”,但对于像这样小而直接的事情,您不需要为您管理依赖注入的框架或容器。如果你无法做出这样的改变,你可以追求one of several alternatives。
你之前可能吃过的地方:
public class UserService implements IUserService {
private final IUserDao userDao;
public UserService() {
this.userDao = new UserDAO();
}
// ...
}
相反,试试这个:
public class UserService implements IUserService {
private final IUserDao userDao;
public UserService() {
this(new UserDAO());
}
/* package private for testing */
UserService(IUserDao userDao) {
this.userDao = userDao;
// ...
}
// ...
}
这会让您将模拟的 UserDAO 安装到真正的 UserService 中:
@BeforeClass // see side note
public static void setUpBeforeClass() throws Exception {
userDAO = mock(IUserDAO.class);
userService = new UserService(userDAO);
}
附带说明一下,如果您在 @Before
方法而不是 @BeforeClass
中实例化 userService
和 userDAO
,将更容易理解您的测试,因为这将防止任何测试的设置干扰任何其他测试。您还可以查看 MockitoJUnitRunner or MockitoRule 以获得测试设置的额外自动化。
这个简单的 mockito 失败了,我不知道为什么?我怀疑设置不完整? 当我在它通过的测试方法中用 userDAO 替换 userService 时,为什么会这样?
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());
}
}
您没有在任何地方将您的模拟 userDAO
安装到您的真实 userService
中;您的 userDAO
表示单个模拟实例,而不是测试中每个 IUserDAO 的替代。
为了让您测试的 userService
使用模拟的 userDAO
,您可能必须接受 userDAO
(或任何其他 IUserDAO 实例)作为 UserService 中的构造函数参数。这种重构将允许使用 UserService(例如生产或测试)的系统来管理或 inject UserService 的 dependencies,而不是让 UserService 创建或者控制它自己的依赖。这种通用技术是“依赖注入”或“控制反转”,但对于像这样小而直接的事情,您不需要为您管理依赖注入的框架或容器。如果你无法做出这样的改变,你可以追求one of several alternatives。
你之前可能吃过的地方:
public class UserService implements IUserService {
private final IUserDao userDao;
public UserService() {
this.userDao = new UserDAO();
}
// ...
}
相反,试试这个:
public class UserService implements IUserService {
private final IUserDao userDao;
public UserService() {
this(new UserDAO());
}
/* package private for testing */
UserService(IUserDao userDao) {
this.userDao = userDao;
// ...
}
// ...
}
这会让您将模拟的 UserDAO 安装到真正的 UserService 中:
@BeforeClass // see side note
public static void setUpBeforeClass() throws Exception {
userDAO = mock(IUserDAO.class);
userService = new UserService(userDAO);
}
附带说明一下,如果您在 @Before
方法而不是 @BeforeClass
中实例化 userService
和 userDAO
,将更容易理解您的测试,因为这将防止任何测试的设置干扰任何其他测试。您还可以查看 MockitoJUnitRunner or MockitoRule 以获得测试设置的额外自动化。