Saturday, October 6, 2012

More testing @Transactional

I have written a little about testing @Transactional in the entry Testing @Transactional (a rip off of Chris Beams).

The test he mentions is called transferServiceIsTransactional but the name promises more that it can hold. Judging from the name of the test one could assume that all methods in the transferService are transactional. However, the interface of the bean is this:

public interface TransferService {

  TransferReceipt transfer(double amount, String srcAcctId, String destAcctId)
throws InsufficientFundsException;

  void setMinimumTransferAmount(double minimumTransferAmount);
}

and the implementation is this:

public class DefaultTransferService implements TransferService {

  //Some code...

  @Override
  public void setMinimumTransferAmount(double minimumTransferAmount) {
    //impl
    //NOTE: there is no @Transactional here
  }

  @Override
  @Transactional
  public TransferReceipt transfer(double amount, String srcAcctId, String dstAcctId)
    throws InsufficientFundsException {
    //impl
  }
}

As you can see the implementation only has @Transactional on one of the methods. This of course means that only that one method is transactional - albeit the bean as such is being advised by the TransactionInterceptor.

One could improve the unit test like this to check whether all methods in an interface are in fact transactional:

@Test
public void transferServiceIsNotTransactional() {
  String methodName = null;

  if (AopUtils.isAopProxy(transferService)) {
    for (Advisor advisor : ((Advised) transferService).getAdvisors()) {
      if (TransactionInterceptor.class.equals(advisor.getAdvice().getClass())) {
       TransactionInterceptor ti = (TransactionInterceptor) advisor.getAdvice();
        for (Method method : TransferService.class.getMethods()) {
          TransactionAttribute transactionAttribute = 
          ti.getTransactionAttributeSource()
          .getTransactionAttribute(method, AopUtils.getTargetClass(transferService));
          if (transactionAttribute == null) {
            methodName = method.getName();
            break;
          }
        }
      }
    }
  }
  assertNull("not all methods in transferService are transactional: ["
    + methodName + "]", methodName);
 }


In all fairness to Chris Beams it should be stated that the code I have commented on above was not the topic of the talk for which he wrote it. So, this is not a critique of the very good seminar.