Test behavior, not method
When code is difficult to test, most like the design needs to be improved
Break up an object when it becomes too large to test easily, or failures too difficult to interpret
Keep interfaces narrow
Keep all dependencies (e.g. time) to application external so they can be provided at test time
Do not mock immutable values
Separate functional concern with multithreading concern, use DeterministicExecutor for thread testing.
Encapsulate functions such as logging:
support.notifyfiltering(....., filter)
Never pass null between objects, instead use:
final Foo::NULL = null;
Bloated constructor might mean object has too many responsibilities
A constructor that has too many non-final parameters can be rewritten such that only the final parameter is set and other dependencies are set in the declaration.
For example:
class Foo {
final Bar arg1;
Bar arg2 = Bar.createInstance();
Bar arg3 = Bar.createInstance();
foo(Bar arg1) {
this.arg1 = arg1;
}
arg2(Bar arg2) {
this.arg2 = arg2;
}
.....
}
For simpler object creation, use builder pattern
class Builder {
static Builder newObject(); // returns a defaut object
Builder withArg1();
Builder withArg2();
Obj build();
}
Setup transaction using common pattern
public class JPATransactor {
private final EntityManager entityManager;
public JPATransactor(EntityManager entityManager) {
this.entityManager = entityManager;
}
public void perform(UnitOfWork unitOfWork) throws Exception {
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
try {
unitOfWork.work();
transaction.commit();
}
catch (PersistenceException e) {
throw e;
}
catch (Exception e) {
transaction.rollback();
throw e;
}
}
}