Mockito org.mockito.exceptions.misusing.UnfinishedStubbingException:检测到未完成的存根
Mockito org.mockito.exceptions.misusing.UnfinishedStubbingException: Unfinished stubbing detected
我想使用 mockito 和 powermockito 为以下 spring MVC 控制器编写单元测试用例。
@Controller
@Configuration
@PropertySource("classpath:project/web/properties/RealTimeAPI.properties")
@RequestMapping("/learnon")
public class ClassManagerController {
private final Logger logger = Logger.getLogger(ClassManagerController.class);
@Autowired
private ClassManagerService classManagerService;
@Autowired
private GroupUserService groupUserService;
@RequestMapping(value = "/teacher", method = RequestMethod.GET)
public ModelAndView showClassDetail(HttpServletRequest request, HttpSession httpSession,
@RequestParam(value = "isbn", required = false) String isbn13,
@RequestParam(value = "classId", required = false) Long classId) {
String redirectUrl = "https://example.com/jsp/Login.jsp?reason=failedLogin&redirectUri=https://example.com/secure/Bookshelf";
String accessDeniedUri = "https://example.com/jsp/AccessDenied.jsp";
if (httpSession.getAttribute("USERID") == null) {
return new ModelAndView("redirect:" + redirectUrl);
}
try {
long userId = Long.parseLong(httpSession.getAttribute("USERID").toString());
UserBean user = classManagerService.getUser(userId);
if (httpSession.getAttribute("SCHOOLID") == null) {
httpSession.setAttribute("SCHOOLID", user.getSchoolId());
}
if (httpSession.getAttribute("FULLFILLMENT_YEAR") == null) {
httpSession.setAttribute("FULLFILLMENT_YEAR", user.getFulfillmentYear());
}
String isbn10 = ISBNUtil.convertIsbn13ToIsbn10(isbn13);
String title = "";
ModelAndView mav = null;
ClassManagerBean classBean = null;
if(classId == null && httpSession.getAttribute("classId") != null){
classId = (Long)httpSession.getAttribute("classId");
}
if(classId != null && classId > 0) {
List<UserBean> userBeanList = classManagerService.getUserList(user.getSchoolId(), classId, isbn10);
classBean = classManagerService.getClassById(classId);
classBean.setUserNumber(userBeanList.size());
title = classBean.getTitle();
//Set the view to ClassManager.jsp
mav = new ModelAndView("ClassManager");
mav.addObject("userList", userBeanList);
boolean authorized = userBeanList.stream().anyMatch(u->u.getUserId() == userId);
if(!authorized){
ModelAndView modelAndView = new ModelAndView("redirect:" + accessDeniedUri);
modelAndView.addObject("accessDenied", "true");
return modelAndView;
}
}else{
title = classManagerService.getTitle(isbn10);
//Set the view to createNewClass.jsp
mav = new ModelAndView("CreateNewClass");
classBean = new ClassManagerBean();
classBean.setLo2Flag(true);
classBean.setIsbn(isbn10);
classBean.setTitle(title);
}
httpSession.setAttribute("searchTitle", title);
httpSession.setAttribute("selectedIsbn", isbn10);
httpSession.setAttribute("classId", classId);
mav.addObject("user", user);
mav.addObject("classBean", classBean);
return mav;
} catch (Exception ex) {
ModelAndView mav2 = new ModelAndView("redirect:" + accessDeniedUri);
mav2.addObject("accessDenied", "true");
logger.error("Exception Occurred, Redirecting to Access Denied...", ex);
return mav2;
}
}
}
我已经为上述 class 编写了以下单元测试用例,并且在我尝试 运行 测试时 运行 收到 UnfinishedStubbingException 异常。
@Test
public void testShowClassDetail1() throws Exception {
HttpServletRequest httpRequest = mock(HttpServletRequest.class);
HttpSession httpSession = mock(HttpSession.class);
Mockito.when(httpSession.getAttribute("USERID")).thenReturn(new String("anyString"));
List<UserBean> list = new ArrayList<UserBean>();
List<UserBean> spyList = Mockito.spy(list);
Mockito.when(classManagerService.getUserList(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString())).thenReturn(spyList);
doReturn(false).when(spyList.stream().anyMatch(u->u.getUserId() == Mockito.anyLong()));
RequestBuilder request = MockMvcRequestBuilders
.get("/learnon/teacher")
.param("isbn", "1234567890123")
.param("classId", "1")
.accept(MediaType.APPLICATION_JSON);
String modalView = "redirect:" + "https://www.example.com/jsp/AccessDenied.jsp";
ResultActions result = mockMvc.perform(request)
.andExpect(status().is3xxRedirection())
.andExpect(view().name(modalView));
}
异常:
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at learnonclassmanager.spring.web.controller.ClassManagerControllerTest.testShowClassDetail1(ClassManagerControllerTest.java:98)
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, you naughty developer!
3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed
at learnonclassmanager.spring.web.controller.ClassManagerControllerTest.testShowClassDetail1(ClassManagerControllerTest.java:98)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:316)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:89)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:97)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:300)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:131)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.access0(PowerMockJUnit47RunnerDelegateImpl.java:59)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner$TestExecutorStatement.evaluate(PowerMockJUnit47RunnerDelegateImpl.java:147)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.evaluateStatement(PowerMockJUnit47RunnerDelegateImpl.java:107)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:288)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:208)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:147)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:121)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:123)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:121)
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)
我试图解决异常,但仍然没有成功。帮我解决这个异常。
编辑:
我删除了以下行
doReturn(false).when(spyList.stream().anyMatch(u->u.getUserId() == Mockito.anyLong()));
并按如下方式更新测试。
@Test
public void testShowClassDetail1() throws Exception {
HttpServletRequest httpRequest = mock(HttpServletRequest.class);
HttpSession httpSession = mock(HttpSession.class);
Mockito.when(httpSession.getAttribute("USERID")).thenReturn(1l);
UserBean beanMock = mock(UserBean.class);
Mockito.when(classManagerService.getUser(1l)).thenReturn(beanMock);
List<UserBean> beanList = new ArrayList<>();
beanList.add(beanMock);
Mockito.when(classManagerService.getUserList(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString())).thenReturn(beanList);
Mockito.when(beanMock.getUserId()).thenReturn(2l);
RequestBuilder request = MockMvcRequestBuilders
.get("/learnon/teacher")
.param("isbn", "1234567890123")
.param("classId", "1")
.accept(MediaType.APPLICATION_JSON);
String modalView = "redirect:" + "https://example.com/jsp/AccessDenied.jsp";
ResultActions result = mockMvc.perform(request)
.andExpect(status().is3xxRedirection())
.andExpect(view().name(modalView));
}
现在我正在关注 AssetionError。
java.lang.AssertionError: View name
expected:https://example.com/jsp/AccessDenied.jsp> but
was:https://example.com/jsp/Login.jsp?reason=failedLogin&redirectUri=https:/
让我们看看下面这行(为便于阅读而格式化):
doReturn(false).when(
spyList.stream()
.anyMatch(u->u.getUserId() == Mockito.anyLong())
);
里面有两个错误,一个是异常报的,另一个我也会解释的
错误 1:对传递给 when
的真实对象的方法调用
为了记录方法调用,您必须将模拟方法调用的结果传递给 when 函数。在您的代码中情况并非如此,因为 stream()
return 的真实对象
见How does mockito when() invocation work?
错误 2:无效使用 ArgumentMatchers
您不能使用 Mockito.anyLong()
作为任意值。这编译为 ArgumentMatchers return 虚拟值(零),但不能按预期工作(与 anyLong() 的比较并不总是正确的)。
见How do Mockito matchers work?
解决方案
模拟的目的是强制在被测方法中满足某些条件。
您的目标是在按 ID 查找用户时 return false。
要实现它,只需使用空列表。这意味着可以删除整个有问题的行。
@RunWith(PowerMockRunner.class)
public class ClassManagerControllerTest {
@Mock
public ClassManagerService classManagerService;
@InjectMocks
public ClassManagerServiceImpl classManagerServiceImpl;
@Mock
public GroupUserService groupUserService;
private MockMvc mockMvc;
@InjectMocks
private ClassManagerController classManagerController;
@Before
public void setUp() {
mockMvc = MockMvcBuilders.standaloneSetup(classManagerController).build();
MockitoAnnotations.initMocks(this);
}
@Test
public void testShowClassDetail1() throws Exception {
UserBean beanMock = mock(UserBean.class);
Mockito.when(classManagerService.getUser(1l)).thenReturn(beanMock);
List<UserBean> beanList = new ArrayList<>();
beanList.add(beanMock);
Mockito.when(classManagerService.getUserList(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString())).thenReturn(beanList);
Mockito.when(beanMock.getUserId()).thenReturn(2l);
RequestBuilder request = MockMvcRequestBuilders
.get("/learnon/teacher")
.param("isbn", "1234567890123")
.param("classId", "1")
.sessionAttr("USERID", 1l)
.accept(MediaType.APPLICATION_JSON);
String modalView = "redirect:" + "https://www.example.com/jsp/AccessDenied.jsp";
ResultActions result = mockMvc.perform(request)
.andExpect(status().is3xxRedirection())
.andExpect(view().name(modalView));
}
}
对我来说,问题的发生是由于 stubbing the behaviour of another mock inside before 'thenReturn' instruction is completed
旧代码是:
Mockito.doReturn(Unit).whenever(mockObj)
.login(userObject, spyMainActivityViewModel.onLoginListener)
我改成了
val listener = spyMainActivityViewModel.onLoginListener
Mockito.doReturn(Unit).whenever(mockObj)
.login(userObject, listener)
(https://github.com/mdhpuri355/Mockito/blob/master/src/main/java/org/mockito/internal/exceptions/Reporter.java。参考unfinishedStubbing()
提示3)
我想使用 mockito 和 powermockito 为以下 spring MVC 控制器编写单元测试用例。
@Controller
@Configuration
@PropertySource("classpath:project/web/properties/RealTimeAPI.properties")
@RequestMapping("/learnon")
public class ClassManagerController {
private final Logger logger = Logger.getLogger(ClassManagerController.class);
@Autowired
private ClassManagerService classManagerService;
@Autowired
private GroupUserService groupUserService;
@RequestMapping(value = "/teacher", method = RequestMethod.GET)
public ModelAndView showClassDetail(HttpServletRequest request, HttpSession httpSession,
@RequestParam(value = "isbn", required = false) String isbn13,
@RequestParam(value = "classId", required = false) Long classId) {
String redirectUrl = "https://example.com/jsp/Login.jsp?reason=failedLogin&redirectUri=https://example.com/secure/Bookshelf";
String accessDeniedUri = "https://example.com/jsp/AccessDenied.jsp";
if (httpSession.getAttribute("USERID") == null) {
return new ModelAndView("redirect:" + redirectUrl);
}
try {
long userId = Long.parseLong(httpSession.getAttribute("USERID").toString());
UserBean user = classManagerService.getUser(userId);
if (httpSession.getAttribute("SCHOOLID") == null) {
httpSession.setAttribute("SCHOOLID", user.getSchoolId());
}
if (httpSession.getAttribute("FULLFILLMENT_YEAR") == null) {
httpSession.setAttribute("FULLFILLMENT_YEAR", user.getFulfillmentYear());
}
String isbn10 = ISBNUtil.convertIsbn13ToIsbn10(isbn13);
String title = "";
ModelAndView mav = null;
ClassManagerBean classBean = null;
if(classId == null && httpSession.getAttribute("classId") != null){
classId = (Long)httpSession.getAttribute("classId");
}
if(classId != null && classId > 0) {
List<UserBean> userBeanList = classManagerService.getUserList(user.getSchoolId(), classId, isbn10);
classBean = classManagerService.getClassById(classId);
classBean.setUserNumber(userBeanList.size());
title = classBean.getTitle();
//Set the view to ClassManager.jsp
mav = new ModelAndView("ClassManager");
mav.addObject("userList", userBeanList);
boolean authorized = userBeanList.stream().anyMatch(u->u.getUserId() == userId);
if(!authorized){
ModelAndView modelAndView = new ModelAndView("redirect:" + accessDeniedUri);
modelAndView.addObject("accessDenied", "true");
return modelAndView;
}
}else{
title = classManagerService.getTitle(isbn10);
//Set the view to createNewClass.jsp
mav = new ModelAndView("CreateNewClass");
classBean = new ClassManagerBean();
classBean.setLo2Flag(true);
classBean.setIsbn(isbn10);
classBean.setTitle(title);
}
httpSession.setAttribute("searchTitle", title);
httpSession.setAttribute("selectedIsbn", isbn10);
httpSession.setAttribute("classId", classId);
mav.addObject("user", user);
mav.addObject("classBean", classBean);
return mav;
} catch (Exception ex) {
ModelAndView mav2 = new ModelAndView("redirect:" + accessDeniedUri);
mav2.addObject("accessDenied", "true");
logger.error("Exception Occurred, Redirecting to Access Denied...", ex);
return mav2;
}
}
}
我已经为上述 class 编写了以下单元测试用例,并且在我尝试 运行 测试时 运行 收到 UnfinishedStubbingException 异常。
@Test
public void testShowClassDetail1() throws Exception {
HttpServletRequest httpRequest = mock(HttpServletRequest.class);
HttpSession httpSession = mock(HttpSession.class);
Mockito.when(httpSession.getAttribute("USERID")).thenReturn(new String("anyString"));
List<UserBean> list = new ArrayList<UserBean>();
List<UserBean> spyList = Mockito.spy(list);
Mockito.when(classManagerService.getUserList(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString())).thenReturn(spyList);
doReturn(false).when(spyList.stream().anyMatch(u->u.getUserId() == Mockito.anyLong()));
RequestBuilder request = MockMvcRequestBuilders
.get("/learnon/teacher")
.param("isbn", "1234567890123")
.param("classId", "1")
.accept(MediaType.APPLICATION_JSON);
String modalView = "redirect:" + "https://www.example.com/jsp/AccessDenied.jsp";
ResultActions result = mockMvc.perform(request)
.andExpect(status().is3xxRedirection())
.andExpect(view().name(modalView));
}
异常:
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at learnonclassmanager.spring.web.controller.ClassManagerControllerTest.testShowClassDetail1(ClassManagerControllerTest.java:98)
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, you naughty developer!
3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed
at learnonclassmanager.spring.web.controller.ClassManagerControllerTest.testShowClassDetail1(ClassManagerControllerTest.java:98)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:316)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:89)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:97)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:300)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:131)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.access0(PowerMockJUnit47RunnerDelegateImpl.java:59)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner$TestExecutorStatement.evaluate(PowerMockJUnit47RunnerDelegateImpl.java:147)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.evaluateStatement(PowerMockJUnit47RunnerDelegateImpl.java:107)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:288)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:208)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:147)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:121)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:123)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:121)
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)
我试图解决异常,但仍然没有成功。帮我解决这个异常。
编辑:
我删除了以下行 doReturn(false).when(spyList.stream().anyMatch(u->u.getUserId() == Mockito.anyLong()));
并按如下方式更新测试。
@Test
public void testShowClassDetail1() throws Exception {
HttpServletRequest httpRequest = mock(HttpServletRequest.class);
HttpSession httpSession = mock(HttpSession.class);
Mockito.when(httpSession.getAttribute("USERID")).thenReturn(1l);
UserBean beanMock = mock(UserBean.class);
Mockito.when(classManagerService.getUser(1l)).thenReturn(beanMock);
List<UserBean> beanList = new ArrayList<>();
beanList.add(beanMock);
Mockito.when(classManagerService.getUserList(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString())).thenReturn(beanList);
Mockito.when(beanMock.getUserId()).thenReturn(2l);
RequestBuilder request = MockMvcRequestBuilders
.get("/learnon/teacher")
.param("isbn", "1234567890123")
.param("classId", "1")
.accept(MediaType.APPLICATION_JSON);
String modalView = "redirect:" + "https://example.com/jsp/AccessDenied.jsp";
ResultActions result = mockMvc.perform(request)
.andExpect(status().is3xxRedirection())
.andExpect(view().name(modalView));
}
现在我正在关注 AssetionError。
java.lang.AssertionError: View name expected:https://example.com/jsp/AccessDenied.jsp> but was:https://example.com/jsp/Login.jsp?reason=failedLogin&redirectUri=https:/
让我们看看下面这行(为便于阅读而格式化):
doReturn(false).when(
spyList.stream()
.anyMatch(u->u.getUserId() == Mockito.anyLong())
);
里面有两个错误,一个是异常报的,另一个我也会解释的
错误 1:对传递给 when
的真实对象的方法调用
为了记录方法调用,您必须将模拟方法调用的结果传递给 when 函数。在您的代码中情况并非如此,因为 stream()
return 的真实对象
见How does mockito when() invocation work?
错误 2:无效使用 ArgumentMatchers
您不能使用 Mockito.anyLong()
作为任意值。这编译为 ArgumentMatchers return 虚拟值(零),但不能按预期工作(与 anyLong() 的比较并不总是正确的)。
见How do Mockito matchers work?
解决方案
模拟的目的是强制在被测方法中满足某些条件。 您的目标是在按 ID 查找用户时 return false。 要实现它,只需使用空列表。这意味着可以删除整个有问题的行。
@RunWith(PowerMockRunner.class)
public class ClassManagerControllerTest {
@Mock
public ClassManagerService classManagerService;
@InjectMocks
public ClassManagerServiceImpl classManagerServiceImpl;
@Mock
public GroupUserService groupUserService;
private MockMvc mockMvc;
@InjectMocks
private ClassManagerController classManagerController;
@Before
public void setUp() {
mockMvc = MockMvcBuilders.standaloneSetup(classManagerController).build();
MockitoAnnotations.initMocks(this);
}
@Test
public void testShowClassDetail1() throws Exception {
UserBean beanMock = mock(UserBean.class);
Mockito.when(classManagerService.getUser(1l)).thenReturn(beanMock);
List<UserBean> beanList = new ArrayList<>();
beanList.add(beanMock);
Mockito.when(classManagerService.getUserList(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString())).thenReturn(beanList);
Mockito.when(beanMock.getUserId()).thenReturn(2l);
RequestBuilder request = MockMvcRequestBuilders
.get("/learnon/teacher")
.param("isbn", "1234567890123")
.param("classId", "1")
.sessionAttr("USERID", 1l)
.accept(MediaType.APPLICATION_JSON);
String modalView = "redirect:" + "https://www.example.com/jsp/AccessDenied.jsp";
ResultActions result = mockMvc.perform(request)
.andExpect(status().is3xxRedirection())
.andExpect(view().name(modalView));
}
}
对我来说,问题的发生是由于 stubbing the behaviour of another mock inside before 'thenReturn' instruction is completed
旧代码是:
Mockito.doReturn(Unit).whenever(mockObj)
.login(userObject, spyMainActivityViewModel.onLoginListener)
我改成了
val listener = spyMainActivityViewModel.onLoginListener
Mockito.doReturn(Unit).whenever(mockObj)
.login(userObject, listener)
(https://github.com/mdhpuri355/Mockito/blob/master/src/main/java/org/mockito/internal/exceptions/Reporter.java。参考unfinishedStubbing()
提示3)