一个简单的银行应用程序:
注意事项:
目标:单元测试服务方法作为maven构建的一部分
单元测试=简单的API测试。例如,服务方法:transfer(int fromAccountId, int toAccountId, double amount)
具有单元测试用例:
fromAccountId
不应为0 toAccountId
不应为0 fromAccountId
!= toAccountId
这些"单元测试"案例不需要数据库连接。
问题:构建服务器没有数据库设置。但是,当执行单元测试用例时,Spring会尝试连接到失败的DB。但是,我们并不需要DB连接来完成这些情况。 (我们有另一组"集成案例" - 这些不是作为正常构建的一部分执行,而是在完全可用的环境下手动执行。如何? - 参见this thread)
问题:
@Transactional
方法时会发生)按要求添加服务层代码:
public class BankManagerImpl implements BankManager {
@Autowired
AccountDao accountDao;
@Autowired
TransactionDao transactionDao;
...
@Override
@Transactional
public void deposit(int accountId, double amount) {
Account a = accountDao.getAccount(accountId);
double bal = a.getAmount();
bal = bal + amount;
a.setAmount(bal);
accountDao.updateAccount(a);
transactionDao.addTransaction(a, TransactionDao.DEPOSIT, amount);
}
@Override
@Transactional
public void withdraw(int accountId, double amount) {
Account a = accountDao.getAccount(accountId);
double bal = a.getAmount();
if(bal < amount) {
throw new RuntimeException("insufficient balance");
}
bal = bal - amount;
a.setAmount(bal);
accountDao.updateAccount(a);
transactionDao.addTransaction(a, TransactionDao.WITHDRAW, amount);
}
@Override
@Transactional
public void transfer(int fromAccountId, int toAccountId, double amount) {
withdraw(fromAccountId, amount);
deposit(toAccountId, amount);
}
...
}
答案 0 :(得分:1)
您需要的是距离集成测试不远的地方。您首先必须构建虚拟 PlatformManager
,并确保它用于您的测试。您可以在另一篇关于SO How do I mock a TransactionManager in a JUnit test, (outside of the container)?的帖子和下面的另一个(部分)示例中找到相关的线索。
当spring按顺序应用ApplicationContext
定义时,最后覆盖其他定义,你只需添加为你测试xml(或JavaConfig)文件在最后一个地方声明那个假{{1}与普通配置中的bean名称相同。
然后从应用程序上下文中获取服务bean并用模拟替换它的Dao(Mockito或你喜欢的)。
根据您必须测试的内容,您必须调整虚拟PlatformManager
,但如果只是添加:
PlatformManager
您将能够控制事务是否已启动,已提交或已回滚。如果您有特殊要求,则必须创建一个真实的public class MockedTransactionManager implements PlatformTransactionManager {
public boolean transactionStarted = false
public commited = false;
public rollbacked = false;
@Override
public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
transactionStarted = true;
return null;
}
@Override
public void commit(TransactionStatus status) throws TransactionException {
commited = true;
}
@Override
public void rollback(TransactionStatus status) throws TransactionException {
commited = true;
}
,而不是传递空值。
答案 1 :(得分:1)
这里的目的是在单元测试期间禁用DB连接。一种方法是按照@Serge Ballesta的回答中提到的Mock事务管理器。我们发现了一种更简单的方法 - 我们在单元测试期间完全禁用事务管理器的加载。这可以通过在应用程序上下文中注释掉下面的行来完成,这可以防止基于注释的事务被踢入。
<!-- <tx:annotation-driven transaction-manager="transactionManager" /> -->
答案 2 :(得分:0)