By kswaughs | Thursday, May 28, 2020

Spring JdbcTemplate RowMapper Junit Test Example

This example shows how to write junit to test Spring RowMapper functionality while mocking JdbcTemplate with Mockito.

This also increases code coverage of RowMapper code.

Below is the DAO class that returns list of users with RowMapper using Lambdas.

Spring JdbcTemplate RowMapper Example with Lambdas
package com.kswaughs.dao;

import java.sql.ResultSet;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import com.kswaughs.beans.User;

@Repository
public class UserDAO {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public List<User> getAllUsers() {

        return jdbcTemplate.query("SELECT ID, NAME, STATUS FROM USER", 
            
            (ResultSet rs, int rowNum) -> {

                User user = new User();

                user.setId(rs.getInt("ID"));
                user.setName(rs.getString("NAME"));
                user.setStatus(rs.getBoolean("STATUS"));

                return user;
            });
        }
    }

Below is the Junit test class to test RowMapper code by mocking JdbcTemplate to return two rows.

Spring JdbcTemplate RowMapper Junit test example
package com.kswaughs.dao;

import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatchers;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import com.kswaughs.beans.User;

@RunWith(MockitoJUnitRunner.class)
public class UserDAOTest {

    @Mock
    private JdbcTemplate jdbcTemplate;

    @InjectMocks
    private UserDAO userDAO;

    @SuppressWarnings("unchecked")
    @Test
    public void testGetAllUsers() {

        Mockito.when(jdbcTemplate.query(
            ArgumentMatchers.anyString(), ArgumentMatchers.any(RowMapper.class)))
            .thenAnswer((invocation) -> {

                RowMapper<User> rowMapper = (RowMapper<User>) invocation.getArgument(1);
                ResultSet rs = Mockito.mock(ResultSet.class);

                // Mock ResultSet to return two rows.
                Mockito.when(rs.getInt(ArgumentMatchers.eq("ID")))
                    .thenReturn(506, 400);
                Mockito.when(rs.getString(ArgumentMatchers.eq("NAME")))
                    .thenReturn("Jim Carrey", "John Travolta");
                Mockito.when(rs.getBoolean(ArgumentMatchers.eq("STATUS")))
                    .thenReturn(true, false);

                List<User> users = new ArrayList<>();
                users.add(rowMapper.mapRow(rs, 0));
                users.add(rowMapper.mapRow(rs, 1));

                return users;
        });

        List<User> users = userDAO.getAllUsers();
        
        // Assert First Row
        assertFirstUser(users.get(0));

        // Assert Second Row
        assertSecondUser(users.get(1));
    }

    public void assertFirstUser(User user) {
        Assert.assertEquals(Integer.valueOf(506), user.getId());
        Assert.assertEquals("Jim Carrey", user.getName());
        Assert.assertTrue(user.isStatus());
    }
    
    public void assertSecondUser(User user) {
        Assert.assertEquals(Integer.valueOf(400), user.getId());
        Assert.assertEquals("John Travolta", user.getName());
        Assert.assertFalse(user.isStatus());
    }
}

Recommend this on


6 comments:

  1. Thanks! By the way, ArgumentMatchers.eq() not needed inside the Mockito.when(), when returning ResultSet rows. Can just pass the columnLabel directly.

    Also `RowMapper rowMapper = (RowMapper) invocation.getArgument(1);` doesn't need to be casted. I think this was the only "generic" line for me so after getting rid of casting, could also get rid of the `@SuppressWarnings("unchecked")` annotation too

    ReplyDelete
  2. This worked perfectly for me

    ReplyDelete
  3. Thank you very much!!!

    ReplyDelete
  4. Thank you very much!!

    ReplyDelete
  5. Should the stakes of the punters exceed the quantity in the meanwhile within the financial institution, the banker is not answerable for the quantity of such excess. In the occasion of their shedding, the croupier pays the punters so as of rotation, so far as the funds in the financial institution will extend; past this, they don't have any 1xbet korean claim. The banker might, nevertheless, in such a case, as an alternative of resting on his proper, declare the stakes accepted, putting up the needed funds to meet them. In such occasion the financial institution thenceforth turns into unlimited, and the banker should hold all stakes provided on any subsequent hand, or surrender the financial institution.

    ReplyDelete