Jdbc 模板和 Spring 的 keyHolder 的 Mockito 测试用例
Mockito Test Case for Jdbc template and Spring's keyHolder
我写了一个测试用例,但在 return KeyHolder.getKey()
行出现空指针异常。
我的测试用例是这样的:
@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));
}
方法如下所示:
@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();
}
我创建了一个接口KeyHolderFactory
:
public interface KeyHolderFactory {
KeyHolder newKeyHolder();
}
而该接口的实现如下:
public class GeneratedKeyHolderFactory implements KeyHolderFactory {
public KeyHolder newKeyHolder() {
return new GeneratedKeyHolder();
}
}
有人可以帮我找到解决办法吗?
下一个是您的问题:
在测试 class 中,您有 Mocked bin KeyHolderFactory
,这是正确的。然后你创建模拟 KeyHolder
,描述它的行为并在被询问时制作 KeyHolderFactory
return KeyHolder
。一切看起来都不错,除了下一个:
在您的代码 class 方法中,您使用 new GeneratedKeyHolder()
创建了新的 KeyHolder
并且这个新的 KeyHolder
与您在测试中拥有的那些模拟实例无关class。这是完全不同的对象。在你的测试中的那个 class - 是一个模拟,并且会遵循你的场景。但是那个,在你测试的 class 方法中,是另一个对象,当你执行 keyHolder.getKey()
.
时,它当然不知道该做什么
解决方案:
您已在测试中注入 KeyHolderFactory
并正确配置了它的行为。只需将其也注入到您的测试 class 中,并在您的方法中使用它来使用 keyHolderFactory.newKeyHolder()
而不是 new GeneratedKeyHolder()
创建 KeyHolder
我写了一个测试用例,但在 return KeyHolder.getKey()
行出现空指针异常。
我的测试用例是这样的:
@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));
}
方法如下所示:
@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();
}
我创建了一个接口KeyHolderFactory
:
public interface KeyHolderFactory {
KeyHolder newKeyHolder();
}
而该接口的实现如下:
public class GeneratedKeyHolderFactory implements KeyHolderFactory {
public KeyHolder newKeyHolder() {
return new GeneratedKeyHolder();
}
}
有人可以帮我找到解决办法吗?
下一个是您的问题:
在测试 class 中,您有 Mocked bin KeyHolderFactory
,这是正确的。然后你创建模拟 KeyHolder
,描述它的行为并在被询问时制作 KeyHolderFactory
return KeyHolder
。一切看起来都不错,除了下一个:
在您的代码 class 方法中,您使用 new GeneratedKeyHolder()
创建了新的 KeyHolder
并且这个新的 KeyHolder
与您在测试中拥有的那些模拟实例无关class。这是完全不同的对象。在你的测试中的那个 class - 是一个模拟,并且会遵循你的场景。但是那个,在你测试的 class 方法中,是另一个对象,当你执行 keyHolder.getKey()
.
解决方案:
您已在测试中注入 KeyHolderFactory
并正确配置了它的行为。只需将其也注入到您的测试 class 中,并在您的方法中使用它来使用 keyHolderFactory.newKeyHolder()
而不是 new GeneratedKeyHolder()
KeyHolder