Amit
Amit

Reputation: 261

Mockito Test Case for Jdbc template and Spring's keyHolder

I wrote a test case but I get a null pointer exception at the return KeyHolder.getKey() line.

My test case looks like this:

@InjectMocks
private UserDAOImpl userDAO;

@Mock
private JdbcTemplate jdbcTemplate;

@Mock
private KeyHolderFactory keyHolderFactory;

@Before
public void setup() {
    MockitoAnnotations.initMocks(this);
    ReflectionTestUtils.setField(userDAO, "jdbcTemplate", jdbcTemplate);
}

@Test
public void testCreateUser() {

    KeyHolder keyHolder = mock(GeneratedKeyHolder.class);

    when(keyHolderFactory.newKeyHolder()).thenReturn(keyHolder);

    User user = getUserInfo();

    Map<String,Object> map = new HashMap<>();
    map.put("id",1L);
    when(keyHolder.getKeys()).thenReturn(map);
    when(keyHolder.getKey()).thenReturn(1L);

    when(jdbcTemplate.update(Mockito.any(PreparedStatementCreator.class), Mockito.any(KeyHolder.class))).thenReturn(1);

    assertEquals(1L, userDAO.createUser(user));
}

And the method looks like this:

 @Override
  public long createUser(User user) {

KeyHolder keyHolder = new GeneratedKeyHolder();

jdbcTemplate.update(connection -> {
  PreparedStatement ps = connection
      .prepareStatement("insert into user (address, first_name,last_name, email, password, phone_number, is_init, is_system_admin, created_at)"
              + " values( ?, ?, ?, ?, ?, ?, ?, ?,?)",
          Statement.RETURN_GENERATED_KEYS);
  ps.setString(1, user.getAddress());
  ps.setString(2, user.getFirstName());
  ps.setString(3, user.getLastName());
  ps.setString(4, user.getEmail());
  ps.setString(5, user.getPassword());
  ps.setString(6, user.getPhone());
  ps.setBoolean(7, user.isActive());
  ps.setBoolean(8, user.isSystemAdmin());
  ps.setDate(9, new Date(Date.from((user.getCreatedAt().toInstant())).getTime()));

  return ps;
}, keyHolder);

return (long) keyHolder.getKey();
  }

I have created an interface KeyHolderFactory:

public interface KeyHolderFactory {
KeyHolder newKeyHolder();
}

And the implementation of this interface is as follows:

public class GeneratedKeyHolderFactory implements KeyHolderFactory {

public KeyHolder newKeyHolder() {
    return new GeneratedKeyHolder();
  }
}

Can someone help me to find a solution?

Upvotes: 3

Views: 2855

Answers (1)

Andriy Rymar
Andriy Rymar

Reputation: 313

Your issue is next :

In test class you have Mocked bin KeyHolderFactory and this is correct. Then you create mocked KeyHolder, describe it's behavior and make KeyHolderFactory return KeyHolder when it is asked. Everything looks OK except next :

On your code class method you create new KeyHolder using new GeneratedKeyHolder() and this new KeyHolder doesn't relate to those mocked instance that you have in your test class. It is absolutely different objects. That one which is in your test class - is a mock, and will follow your scenario. But that one, in your tested class method, is another object, which of course don't know what to do when you execute keyHolder.getKey().

Solution :

You have injected KeyHolderFactory in your test and well configured it's behavior. Just inject this into your test class as well and use it in your method to create KeyHolder using keyHolderFactory.newKeyHolder() instead of new GeneratedKeyHolder()

Upvotes: 3

Related Questions