如何用Mockito模拟SimpleDateFormat.parse()抛出异常测试Dao方法
作为Java/Mockito新手,你要验证saveTemplate方法捕获ParseException并抛出SQLException的逻辑,这个场景很常见,我来帮你梳理整个过程:
你的目标场景
先看Dao核心代码里的关键逻辑:
public Template saveTemplate(Template template) throws SQLException { logger.debug("Saving template details into the db ", template.getTemplateName()); SimpleDateFormat dt = new SimpleDateFormat("yyyyy-mm-dd hh:mm:ss"); Long date = 0L; try { date = dt.parse(template.getStartTime()).getTime(); } catch (ParseException e) { throw new SQLException("Error while processing date " + template.getTemplateName()); } // 后续代码... }
我们需要触发try块里的ParseException,进而验证catch块抛出的SQLException。
你之前踩的坑
1. 用@InjectMocks注入SimpleDateFormat失败
报错信息:
org.mockito.exceptions.base.MockitoException: Cannot instantiate @InjectMocks field named 'simpleDateFormat' of type 'class java.text.SimpleDateFormat'. You haven't provided the instance at field declaration so I tried to construct the instance. However the constructor or the initialization block threw an exception : null
原因很简单:SimpleDateFormat的构造函数必须传入格式字符串参数,Mockito无法自动无参实例化它,所以@InjectMocks在这里行不通。
2. 用@Mock模拟SimpleDateFormat触发参数匹配器错误
报错信息:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Misplaced or misused argument matcher detected here: ...
本质问题是:SimpleDateFormat继承自DateFormat,而DateFormat的parse方法是final方法。Mockito默认不能mock final方法(除非开启Mockito的final方法mock功能),所以你尝试mock它的parse方法时,Mockito无法正确处理,进而抛出参数匹配器的错误提示(这个提示有点误导,但核心是你mock了不能被mock的方法)。
成功的解决方案:让模板返回无效日期字符串
不需要去mockSimpleDateFormat,直接让Template.getStartTime()返回一个无法被解析的日期字符串,这样真实的parse方法就会抛出ParseException,自然触发catch块的SQLException。
你的测试代码已经成功,整理后的版本:
@Test(expected = SQLException.class) public void test_save_template_date_parse_error() throws ParseException, SQLException { initMocks(this); // 模拟Template对象,让它返回无效日期 Template templateMock = Mockito.mock(Template.class); Mockito.when(templateMock.getStartTime()).thenReturn("invalid"); // 准备其他依赖(比如jdbcTemplate,根据你的实际情况调整) given(jdbcTemplate.getJdbcOperations()).willReturn(jdbcOperations); // 调用方法,预期抛出SQLException templateDAOImpl.saveTemplate(templateMock); }
这个方案的优势:
- 完全贴合真实代码逻辑,不需要mock底层的日期解析类
- 代码简洁,容易维护,符合Mockito的测试理念:mock依赖,而不是底层JDK类
内容的提问来源于stack exchange,提问作者JESii

