简体   繁体   中英

Mocking a Dateformat (SimpleDateFormat) in JUnit tests

Im trying to test a DAO function which uses a DateFormat (SimpleDateFormat). When I try to run the test im getting:

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)

This points to : election.setStartDate(df.format(rs.getDate("startDate"))); in the DAO

This it the test code:

@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");
    }
}

This is the function in the 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;
    }

I have tried some examples i've found online, but I'm still getting the same error. I also have read that DateFormat is a final function and cannot be mocked. There where some workarounds, but didn't work for me. I'm not sure I've implemented those workaround correctly.

Could you please provide me the code to fix this NullPointer? Thanks in advance!

First of all, I don't see anything mocking rs.getDate() so that is going to return null. That will probably cause problems with both mocked and real instances of SimpleDateFormat . You can address that like this:

// (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);

That combined when(formatter.format(any())).thenReturn("'2018-11-12 00:00'") might get you past the exception. It looks, though, like you are creating a real SimpleDateFormat inside AdminDaoImpl and your mocked one wouldn't get used at all. So you will have to either modify AdminDaoImpl to allow you to inject the SimpleDateFormat or write your tests so that they do not know that AdminDaoImpl uses SimpleDateFormat .

Personally, I wouldn't mock the SimpleDateFormat at all. Instead, I would treat it as an internal implementation detail of AdminDaoImpl . I would mock the result set to return the date and then verify that the ElectionListResponse has the expected date. That would look something like this:

// (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());

These tests confirm that the Election has its startDate mapped properly from the result set, but they don't care at all how AdminDaoImpl does it.

If you're mocking DateFormat then why you're creating SimpleDateFormat object. You should provide when() and thenReturn() wherever you're using SimpleDateFormat object. All the dependencies should be mocked, no actual object creation would be there.

No database interaction would be there while unit testing of DAO, you can easily mock the db layer.

when(df.format("your_date").thenReturn(some_value);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM