Mockito:@InjectMocks(OK)与模拟对象的构造函数(NPE)

Mockito: @InjectMocks (OK) vs constructor of mocked objects (NPE)

这里是应该测试的class:

public class UserService {
    private final UserDAO userDAO;
    private final TransactionManager transactionManager;

    public UserService(UserDAO userDAO, TransactionManager transactionManager) {
        this.userDAO = userDAO;
        this.transactionManager = transactionManager;
    }

    public boolean isUserEmailUnique(HttpServletRequest req, Connection connection) {
        User user = transactionManager //---- NPE if no InjectMocks was done -----
                .doInTransaction(connection, (con) ->
                userDAO.getUserByEmail(con, req.getParameter(Attributes.EMAIL)));

        return Objects.isNull(user);
    }

这里是测试class:

@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {
    @Mock HttpServletRequest mockedReq;
    @Mock TransactionManager mockedTransactionManager;
    @Mock Connection mockedConnection;
    
    UserService userService; // QUESTION IS ABOUT THAT OBJECT

    @Test
    public void ifSuchUserWasNotFound_ThenEmailIsUnique() {
        doReturn(new User()).when(mockedTransactionManager).doInTransaction(any(Connection.class), any(TransactionOperation.class));
        assertFalse(userService.isUserEmailUnique(mockedReq, mockedConnection));

        doReturn(null).when(mockedTransactionManager).doInTransaction(any(Connection.class), any(TransactionOperation.class));
        assertTrue(userService.isUserEmailUnique(mockedReq, mockedConnection));
    }

如果我将模拟注入到被测试的 userService 中,如下所示,这个测试工作正常。

@InjectMocks UserService userService;

但是如果我创建一个新实例并将模拟对象传递给构造函数,如下所示,在测试的 class

中会抛出一个关于 transactionManager 的 NullPointerException
// no @InjectMocks
UserService userService = new UserService(mockedUserDAO, mockedTransactionManager);

这不应该是一回事吗?也许我是一个坏人 reader,但官方 article 并没有说 @InjectMocks 应该做一些特殊的事情,这对于基本构造函数是不可用的。

知道为什么传递给构造函数的模拟对象仍然为空吗?

按照事件顺序:

UserService userService = new UserService(mockedUserDAO, mockedTransactionManager);

创建实例作为创建测试 class 实例的一部分,但 mockito 尚未 运行 因此 mockedUserDAOmockedTransactionManager 为空。

将实例创建移至设置方法:

UserService userService;

@Before
public void prepareTest() {
    userService = new UserService(mockedUserDAO, mockedTransactionManager);
}