gpt4 book ai didi

java - 使用 Mockito 模拟 Spring 的 jdbc KeyHolder

转载 作者:行者123 更新时间:2023-12-01 17:30:25 24 4
gpt4 key购买 nike

我需要你的帮助来解决一个问题。我的 DAO 类中有这样的方法来保存角色:

@Repository(value="jdbcRoleDAO")
@Transactional(propagation=Propagation.SUPPORTS, readOnly=true, rollbackFor=Exception.class)
public class JdbcRoleDAO implements RoleDAO {

@Autowired
private JdbcTemplate jdbcTemplate;

@Autowired
private DBLogger<Role> dbLogger;

/**
* @throws DublicateEntryException if object with specified unique for application field already
* exists in DB.
*/
@CacheEvict(value = "roles", allEntries = true)
@Transactional(propagation=Propagation.REQUIRED, readOnly=false, rollbackFor=Exception.class)
@Override
public Role save(final Role role) {

if (this.getRoleByName(role.getName()) != null) {
throw new DublicateEntryException("Record with specified role name already exists in application.");
}

KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(new PreparedStatementCreator() {

@Override
public PreparedStatement createPreparedStatement(Connection connection)
throws SQLException {

PreparedStatement ps = connection.prepareStatement(SQL_INSERT_ROLE, new String[]{"ID"});

ps.setString(1, role.getName());
ps.setString(2, role.getDesription());
ps.setObject(3, (role.getParentRole()!=null)?role.getParentRole().getId():null);
ps.setString(4, role.getPrivilege().toString());

return ps;
}
}, keyHolder);

Long key = (Long) keyHolder.getKey();
if (key != null) {
role.setId(key);
} else {
role.setId(-1);
}

// Add information about operation to log table
dbLogger.logBasicOperation(role, OperationName.CREATE);

return role;
}
...
}

我想使用 Mockito 为这个方法编写单元测试。目前看起来是这样的:

@RunWith(MockitoJUnitRunner.class)
public class JdbcRoleDAOTest {

private static final long TEST_ROLE_ID = 1L;
private static final int TEST_ROLE_VERSION = 7;

@Mock
private DBLogger<Role> dbLogger;

@Mock
private JdbcTemplate jdbcTemplate;

@InjectMocks
private JdbcRoleDAO roleDAO;

/**
* test role that is used in all methods.
*/
private Role role;

@Before
public void setUp(){
// Create a test role object
role = new Role();
role.setId(TEST_ROLE_ID);
role.setName("TEST");
role.setDesription("Test role");
role.setPrivilege(Privilege.DEFAULT);
role.setVersion(TEST_ROLE_VERSION);

// Return correct version of the object
Mockito.when(jdbcTemplate.queryForInt(JdbcRoleDAO.SQL_GET_VERSION, TEST_ROLE_ID))
.thenReturn(TEST_ROLE_VERSION);
}

@Test
public void testSave() {
Assert.assertNotNull(role);

roleDAO.save(role);

InOrder inOrder = Mockito.inOrder(jdbcTemplate, dbLogger);

// Verify execution of the conditions.
inOrder.verify(jdbcTemplate, Mockito.times(1)).update(Mockito.any(PreparedStatementCreator.class),
Mockito.any(KeyHolder.class));

inOrder.verify(dbLogger, Mockito.times(1)).logBasicOperation(role, OperationName.CREATE);

/*
* Expected -1 because I can't mock KeyHolder and should be returned -1 value (because
* KeyHolder will return null instead of key)
*/
Assert.assertEquals("Generated id is wrong!", -1, role.getId());
}

}

问题在于我想以某种方式模拟 KeyHolder 但我不知道如何更好地做到这一点。如您所见,现在 KeyHolder 实例是在 save 方法中创建的,这是一个主要困难。我考虑过使用 Spring 的“原型(prototype)”范围注入(inject) KeyHolder,但据我了解,当很少有用户同时尝试保存新角色时,这可能会导致问题。我也尝试做这样的事情:

Mockito.when(jdbcTemplate.update(Mockito.any(PreparedStatementCreator.class), 
Mockito.any(KeyHolder.class)))
.thenAnswer(new Answer<Void>() {

@Override
public Void answer(InvocationOnMock invocation)
throws Throwable {

Object[] arguments = invocation.getArguments();
for (int i=0; i<arguments.length; i++) {
if (arguments[i] instanceof KeyHolder) {
KeyHolder keyHolder = (KeyHolder) arguments[i];

KeyHolder spyKeyHolder = Mockito.spy(keyHolder);
Mockito.when(spyKeyHolder.getKey()).thenReturn(TEST_GENERATED_ID);
Mockito.doReturn(TEST_GENERATED_ID).when(spyKeyHolder).getKey();
}
}

return null;
}
});

但这行不通。也许有人可以给我一个建议,如何模拟(或监视)KeyHolder而不将其从保存方法移出? Mockito 中是否有一些功能可以实现这一点?还是不可能?

提前谢谢

最佳答案

您可以创建以下界面:

public interface KeyHolderFactory {
KeyHolder newKeyHolder();
}

然后在 JdbcRoleDAO 中添加一个 KeyHolderFactory 字段,通过生产中的依赖项注入(inject)来填充,并在测试时手动使用模拟来填充。生产实现很简单,您可以使用它的单个实例(单例):

public class GeneratedKeyHolderFactory implements KeyHolderFactory {
public KeyHolder newKeyHolder() {
return new GeneratedKeyHolder();
}
}

在您将拥有的方法内

...
KeyHolder keyHolder = factory.newKeyHolder();
...

关于java - 使用 Mockito 模拟 Spring 的 jdbc KeyHolder,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11615298/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com