
本文旨在解决在使用 Mockito 框架进行单元测试时,thenReturn() 方法无法正常工作,导致模拟对象返回空值的问题。通过示例代码和详细步骤,帮助开发者正确配置和使用 Mockito,确保单元测试的有效性。
在使用 Mockito 进行单元测试时,经常会遇到 thenReturn() 方法失效,导致模拟对象返回 null 的情况。这个问题通常是由于 Mockito 的初始化不正确导致的。下面将详细介绍如何正确配置和使用 Mockito,解决 thenReturn() 失效的问题。
问题分析
当 loginDao.getAdminDetails(anyString(), anyString()) 返回 null,并且抛出 UnnecessaryStubbingException 异常时,说明 Mockito 没有正确地初始化 Mock 对象,或者 Mock 对象没有被正确地注入到被测试的类中。
解决方案
解决这个问题的关键在于正确初始化 Mockito 的 Mock 对象,并将它们注入到被测试的类中。以下是两种常用的解决方案:
1. 使用 MockitoAnnotations.initMocks(this)
这种方法需要在测试类的 setUp 方法中使用 MockitoAnnotations.initMocks(this) 来初始化 Mockito。这会扫描测试类中所有带有 @Mock 注解的字段,并创建它们的 Mock 对象。同时,它还会扫描带有 @InjectMocks 注解的字段,并将 Mock 对象注入到这些字段中。
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
class LoginControllerTest {
@InjectMocks
LoginController loginController;
@Mock
CustomerDao customerDao;
@Mock
Customer customer;
@Mock
InvoiceDao invoiceDao;
@Mock
DashboardDao dashboardDao;
@Mock
LoginDao loginDao;
@Mock
Admin admin;
@BeforeEach
void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
void testLogin() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
request.setParameter("password", "pass");
request.setParameter("username", "uname");
when(loginDao.getAdminDetails(anyString(), anyString())).thenReturn(admin);
ModelAndView modelAndView = loginController.login(request, response);
assertNotNull(modelAndView);
}
}注意事项:
- 确保在测试方法执行之前调用 MockitoAnnotations.initMocks(this)。
- 将 setUp 方法使用 @BeforeEach 注解标记,以确保在每个测试方法执行之前都会执行初始化操作。
2. 使用 JUnit Runner 初始化 Mockito
另一种方法是使用 JUnit 提供的 Runner 来初始化 Mockito。这可以通过在测试类上添加 @RunWith(MockitoJUnitRunner.class) 注解来实现。
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
class LoginControllerTest {
@InjectMocks
LoginController loginController;
@Mock
CustomerDao customerDao;
@Mock
Customer customer;
@Mock
InvoiceDao invoiceDao;
@Mock
DashboardDao dashboardDao;
@Mock
LoginDao loginDao;
@Mock
Admin admin;
@Test
void testLogin() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
request.setParameter("password", "pass");
request.setParameter("username", "uname");
when(loginDao.getAdminDetails(anyString(), anyString())).thenReturn(admin);
ModelAndView modelAndView = loginController.login(request, response);
assertNotNull(modelAndView);
}
}注意事项:
- 确保添加了 org.mockito.junit.MockitoJUnitRunner 依赖。
- 这种方法不需要显式调用 MockitoAnnotations.initMocks(this),JUnit 会自动完成初始化。
示例代码解释
- @InjectMocks 注解:用于标记需要注入 Mock 对象的类,例如 LoginController。
- @Mock 注解:用于标记需要创建 Mock 对象的类,例如 LoginDao 和 Admin。
- when(loginDao.getAdminDetails(anyString(), anyString())).thenReturn(admin):这行代码用于指定当调用 loginDao.getAdminDetails() 方法时,返回 admin 对象。anyString() 方法表示匹配任何字符串参数。
- assertNotNull(modelAndView):这行代码用于断言 login() 方法返回的 ModelAndView 对象不为空。
总结
通过正确初始化 Mockito,并使用 @Mock 和 @InjectMocks 注解,可以有效地解决 thenReturn() 方法失效的问题。选择哪种初始化方式取决于个人偏好和项目需求。 无论选择哪种方法,都需要确保 Mock 对象被正确地创建和注入到被测试的类中,才能保证单元测试的有效性。 此外,确保你的 Mockito 和 JUnit 版本兼容,避免因版本问题导致初始化失败。










