常规单元测试通过但 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 中实例化 userServiceuserDAO,将更容易理解您的测试,因为这将防止任何测试的设置干扰任何其他测试。您还可以查看 MockitoJUnitRunner or MockitoRule 以获得测试设置的额外自动化。