A simple banking application:
Points to note:
- Using Spring+JPA with EclipseLink as JPA provider
- EntityManager is injected into BaseDaoImpl using @PersistenceContext
- DAOs are autowired into the Service bean
- @Transactional annotation used at service methods
Objective: Unit-test Service methods as part of maven build
Unit-test = simple API testing. For example, a service method: transfer(int fromAccountId, int toAccountId, double amount)
has unit-test cases:
fromAccountId
should not be 0toAccountId
should not be 0fromAccountId
!=toAccountId
- `amount is greater than 0
- etc.
These "unit-test" cases do not require DB connection.
Problem: Build server has no DB setup. However, when the unit-test case is executed, Spring tries to connect to DB which fails. However, we do not really need DB connection for these cases to go through. (We have another set of "integration cases" - these are not executed as part of the normal build but will be executed manually with full environment available. How? - See this thread)
Questions:
- What are the best practices to execute these kinds of unit test cases?
- Can we force Spring not to make DB connection till the last minute it is actually needed? (Right now, it does when it encounters
@Transactional
method)
Adding Service Layer code as requested:
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);
}
...
}