如何模拟由 MyBatis 初始化的接口引用?

How to mock an interface's reference which is initialized by MyBatis?

在标记此 Answer 的副本之前,请理解该答案无法解决我的问题。答案给出了我在当前方法中使用 when() 的解决方案。在我的问题中,UserDao 正在初始化,否则无法传递被测方法内部和模拟对象。


有一个接口的引用是MyBatis初始化的。我不能在测试中直接模拟它,因为该对象没有传递到测试的主题中。我必须通过模拟构造函数来 PowerMock 它。因为没有调用接口的构造函数,PowerMock 抛出异常。

java.lang.ArrayIndexOutOfBoundsException: 0

    at org.powermock.api.mockito.internal.expectation.AbstractConstructorExpectationSetup.withAnyArguments(AbstractConstructorExpectationSetup.java:100)

这是代码的样子

class UserServiceTest{

    @AutoWired
    UserService userService;

    @Mock
    UserDao userDao;//This is a reference to the interface (UserDao) which is mapped using MyBatis

    @Before
    public void setUp() throws Exception {
           MockitoAnnotations.initMocks(this);
           //The Program fails at the below statement
           PowerMockito.whenNew(UserDao.class).withAnyArguments().thenReturn(userDao);        
    @Test
    public void testFetchDetails() throws Exception {
          when(userDao.fetchDetails(any(ParameterOne.class)).thenReturn(null);
          assertThat(userService.fetchDetails(new ParameterOne())).isNull();
    }

}

如果我 运行 没有 PowerMock 的程序,实际的数据库被访问并且 returns 正确的结果。访问数据库还会导致测试速度减慢 运行 时间增加到 500 毫秒。

如何模拟 UserDao userDao?如果我不能模拟在这种情况下如何执行单元测试。我无法更改正在测试的代码。

P.S。如果您仍然建议我避免使用 PowerMock,请在这种情况下提出 "better" 替代方案。

P.P.S 请注意,我不是在测试 Dao 层,而是在测试使用 Dao 层的服务,因此,我必须模拟 DaoLayer 来检查服务的行为是否正确。

该应用程序是 spring-引导应用程序。我将 @InjectMocks 用于测试中的 class,将 @Mock 用于任何需要模拟的对象。

@RunWith(SpringRunner.class)    
class UserServiceTest{
    @InjectMocks
    UserService userService;

    @Mock
    UserDao userDao;//This is a reference to the interface (UserDao) which is mapped using MyBatis

    ...
}

这有效,我可以直接在模拟对象上使用 when()/given()。