在 JUnit 测试中模拟 Dateformat (SimpleDateFormat)
Mocking a Dateformat (SimpleDateFormat) in JUnit tests
我正在尝试测试使用 DateFormat (SimpleDateFormat) 的 DAO 函数。当我尝试 运行 测试时,我得到:
java.lang.NullPointerException
at java.util.Calendar.setTime(Calendar.java:1770)
at java.text.SimpleDateFormat.format(SimpleDateFormat.java:943)
at java.text.SimpleDateFormat.format(SimpleDateFormat.java:936)
at java.text.DateFormat.format(DateFormat.java:345)
这指向:election.setStartDate(df.format(rs.getDate("startDate")));在 DAO
这是测试代码:
@RunWith(MockitoJUnitRunner.class)
public class AdminDaoImplTest {
@Mock
Connection mockConn;
@Mock
PreparedStatement mockPreparedStmnt;
@Mock
ResultSet mockResultSet;
@Mock
DateFormat formatter;
@InjectMocks
private AdminDao adminDao = new AdminDaoImpl();
@Mock
private SQLConnection mockSqlConnection;
@BeforeClass
public static void setUpClass() throws Exception {
}
@AfterClass
public static void tearDownClass() {
}
@Before
public void init() throws SQLException {
when(mockSqlConnection.getConnection()).thenReturn(mockConn);
when(mockConn.prepareStatement(anyString())).thenReturn(mockPreparedStmnt);
when(mockPreparedStmnt.executeQuery()).thenReturn(mockResultSet);
when(mockResultSet.next()).thenReturn(Boolean.TRUE, Boolean.FALSE);
when(formatter.format(any())).thenReturn("'2018-11-12 00:00'");
}
@After
public void tearDown() {
}
@Test
public void testGetElectionsNoExceptions() throws SQLException {
ElectionListResponse electionListResponse = new ElectionListResponse();
adminDao.getElections('>' );
//verify and assert
verify(mockConn, times(1)).prepareStatement(anyString());
verify(mockPreparedStmnt, times(1)).executeQuery();
verify(mockResultSet, times(1)).next();
verify(mockResultSet, times(1)).getInt("id");
verify(mockResultSet, times(1)).getString("name");
verify(mockResultSet, times(1)).getDate("startDate");
verify(mockResultSet, times(1)).getDate("endDate");
}
}
这是DAO中的函数:
@Override
public ElectionListResponse getElections(char selector) {
ElectionListResponse electionListResponse = new ElectionListResponse();
String query = NamedQueries.GET_ELECTIONS_BEGIN + selector + NamedQueries.GET_ELECTIONS_END;
try {
con = sqlConnection.getConnection();
stmt = con.prepareStatement(query);
rs = stmt.executeQuery();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
while (rs.next()) {
Election election = new Election();
election.setElectionID(rs.getInt("id"));
election.setElectionName(rs.getString("name"));
election.setStartDate(df.format(rs.getDate("startDate")));
election.setEndDate(df.format(rs.getDate("endDate")));
electionListResponse.addElection(election);
}
return electionListResponse;
} catch (SQLException e) {
LOGGER.log(Level.SEVERE, "Cant get elections. ", e);
} finally {
closeConnection();
}
return null;
}
我已经尝试了一些在网上找到的例子,但我仍然遇到同样的错误。我也读过 DateFormat 是一个最终函数,不能被模拟。那里有一些解决方法,但对我不起作用。我不确定我是否正确实施了这些解决方法。
能否请您提供修复此 NullPointer 的代码?提前致谢!
如果您在模拟 DateFormat 那么为什么要创建 SimpleDateFormat 对象。您应该在使用 SimpleDateFormat 对象的任何地方提供 when() 和 thenReturn() 。所有依赖项都应该被模拟,不会有实际的对象创建。
DAO单元测试时不会有数据库交互,可以轻松mock db层。
when(df.format("your_date").thenReturn(some_value);
首先,我没有看到任何模拟 rs.getDate() 的内容,因此 return 将为空。这可能会导致 SimpleDateFormat
的模拟实例和真实实例出现问题。您可以这样解决:
// (I am using the deprecated constructor for simplicity)
java.sql.Date startDate = new java.sql.Date(2018, 6, 5);
Mockito.when(mockResultSet.getDate("startDate")).thenReturn(startDate);
结合 when(formatter.format(any())).thenReturn("'2018-11-12 00:00'")
可能 可以让您克服异常。不过,看起来您正在 AdminDaoImpl
中创建一个真正的 SimpleDateFormat
而您的模拟对象根本不会被使用。因此,您将不得不修改 AdminDaoImpl
以允许您注入 SimpleDateFormat
或编写您的测试,以便他们不知道 AdminDaoImpl
使用 SimpleDateFormat
.
就个人而言,我根本不会嘲笑 SimpleDateFormat。相反,我会将其视为 AdminDaoImpl
的内部实现细节。我会将结果集模拟为 return 日期,然后验证 ElectionListResponse
是否具有预期日期。那看起来像这样:
// (I am using the deprecated constructor for simplicity)
java.sql.Date startDate = new java.sql.Date(2018, 6, 5);
Mockito.when(mockResultSet.getDate("startDate")).thenReturn(startDate);
ElectionListResponse response = adminDao.getElections('>' );
Election firstElection = response.getFirst() // Or whatever method(s) get you the first one
Assert.assertEquals("2018-06-05 00:00", firstElection.getStartDate());
这些测试确认 Election
的 startDate
从结果集中正确映射,但他们根本不关心 AdminDaoImpl
是如何做到的。
我正在尝试测试使用 DateFormat (SimpleDateFormat) 的 DAO 函数。当我尝试 运行 测试时,我得到:
java.lang.NullPointerException
at java.util.Calendar.setTime(Calendar.java:1770)
at java.text.SimpleDateFormat.format(SimpleDateFormat.java:943)
at java.text.SimpleDateFormat.format(SimpleDateFormat.java:936)
at java.text.DateFormat.format(DateFormat.java:345)
这指向:election.setStartDate(df.format(rs.getDate("startDate")));在 DAO
这是测试代码:
@RunWith(MockitoJUnitRunner.class)
public class AdminDaoImplTest {
@Mock
Connection mockConn;
@Mock
PreparedStatement mockPreparedStmnt;
@Mock
ResultSet mockResultSet;
@Mock
DateFormat formatter;
@InjectMocks
private AdminDao adminDao = new AdminDaoImpl();
@Mock
private SQLConnection mockSqlConnection;
@BeforeClass
public static void setUpClass() throws Exception {
}
@AfterClass
public static void tearDownClass() {
}
@Before
public void init() throws SQLException {
when(mockSqlConnection.getConnection()).thenReturn(mockConn);
when(mockConn.prepareStatement(anyString())).thenReturn(mockPreparedStmnt);
when(mockPreparedStmnt.executeQuery()).thenReturn(mockResultSet);
when(mockResultSet.next()).thenReturn(Boolean.TRUE, Boolean.FALSE);
when(formatter.format(any())).thenReturn("'2018-11-12 00:00'");
}
@After
public void tearDown() {
}
@Test
public void testGetElectionsNoExceptions() throws SQLException {
ElectionListResponse electionListResponse = new ElectionListResponse();
adminDao.getElections('>' );
//verify and assert
verify(mockConn, times(1)).prepareStatement(anyString());
verify(mockPreparedStmnt, times(1)).executeQuery();
verify(mockResultSet, times(1)).next();
verify(mockResultSet, times(1)).getInt("id");
verify(mockResultSet, times(1)).getString("name");
verify(mockResultSet, times(1)).getDate("startDate");
verify(mockResultSet, times(1)).getDate("endDate");
}
}
这是DAO中的函数:
@Override
public ElectionListResponse getElections(char selector) {
ElectionListResponse electionListResponse = new ElectionListResponse();
String query = NamedQueries.GET_ELECTIONS_BEGIN + selector + NamedQueries.GET_ELECTIONS_END;
try {
con = sqlConnection.getConnection();
stmt = con.prepareStatement(query);
rs = stmt.executeQuery();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
while (rs.next()) {
Election election = new Election();
election.setElectionID(rs.getInt("id"));
election.setElectionName(rs.getString("name"));
election.setStartDate(df.format(rs.getDate("startDate")));
election.setEndDate(df.format(rs.getDate("endDate")));
electionListResponse.addElection(election);
}
return electionListResponse;
} catch (SQLException e) {
LOGGER.log(Level.SEVERE, "Cant get elections. ", e);
} finally {
closeConnection();
}
return null;
}
我已经尝试了一些在网上找到的例子,但我仍然遇到同样的错误。我也读过 DateFormat 是一个最终函数,不能被模拟。那里有一些解决方法,但对我不起作用。我不确定我是否正确实施了这些解决方法。
能否请您提供修复此 NullPointer 的代码?提前致谢!
如果您在模拟 DateFormat 那么为什么要创建 SimpleDateFormat 对象。您应该在使用 SimpleDateFormat 对象的任何地方提供 when() 和 thenReturn() 。所有依赖项都应该被模拟,不会有实际的对象创建。
DAO单元测试时不会有数据库交互,可以轻松mock db层。
when(df.format("your_date").thenReturn(some_value);
首先,我没有看到任何模拟 rs.getDate() 的内容,因此 return 将为空。这可能会导致 SimpleDateFormat
的模拟实例和真实实例出现问题。您可以这样解决:
// (I am using the deprecated constructor for simplicity)
java.sql.Date startDate = new java.sql.Date(2018, 6, 5);
Mockito.when(mockResultSet.getDate("startDate")).thenReturn(startDate);
结合 when(formatter.format(any())).thenReturn("'2018-11-12 00:00'")
可能 可以让您克服异常。不过,看起来您正在 AdminDaoImpl
中创建一个真正的 SimpleDateFormat
而您的模拟对象根本不会被使用。因此,您将不得不修改 AdminDaoImpl
以允许您注入 SimpleDateFormat
或编写您的测试,以便他们不知道 AdminDaoImpl
使用 SimpleDateFormat
.
就个人而言,我根本不会嘲笑 SimpleDateFormat。相反,我会将其视为 AdminDaoImpl
的内部实现细节。我会将结果集模拟为 return 日期,然后验证 ElectionListResponse
是否具有预期日期。那看起来像这样:
// (I am using the deprecated constructor for simplicity)
java.sql.Date startDate = new java.sql.Date(2018, 6, 5);
Mockito.when(mockResultSet.getDate("startDate")).thenReturn(startDate);
ElectionListResponse response = adminDao.getElections('>' );
Election firstElection = response.getFirst() // Or whatever method(s) get you the first one
Assert.assertEquals("2018-06-05 00:00", firstElection.getStartDate());
这些测试确认 Election
的 startDate
从结果集中正确映射,但他们根本不关心 AdminDaoImpl
是如何做到的。