Dependency injection could provide the delegate, and specify a default implementation -- which could be overridden in unit tests.
For example, the Guice framework supports an annotation on the interface for its default implementation, which can be overridden by an explicit binding in unit tests.
@ImplementedBy( ConcreteStuffDoer.class )
public interface StuffDoer{
void doStuff();
}
public class ConcreteStuffDoer implements StuffDoer {
public void doStuff(){ ... }
}
public class MyClass implements StuffDoer{
@Inject StuffDoer m_delegate;
public void doStuff(){ m_delegate.doStuff(); }
}
This does introduce the requirement that creating an instance of MyClass requires a Guice method rather than simply new.