Just to make @Robin's suggestion of a strategy pattern more concrete: (Notice that the public API of your original question remains unchanged.)
public class MyLegacyClass {
private static Strategy strategy = new JNDIStrategy();
public static SomeLegacyClass doSomeLegacyStuff(SomeOtherLegacyClass legacyObj) {
// legacy logic
SomeLegacyClass result = strategy.doSomeStuff(legacyObj);
// more legacy logic
return result;
}
static void setStrategy(Strategy strategy){
MyLegacyClass.strategy = strategy;
}
}
interface Strategy{
public SomeLegacyClass doSomeStuff(SomeOtherLegacyClass legacyObj);
}
class JNDIStrategy implements Strategy {
private static final String jndiName = "java:comp/env/jdbc/LegacyDataSource";
public SomeLegacyClass doSomeStuff(SomeOtherLegacyClass legacyObj) {
// do stuff using jndiName
}
}
...and JUnit test. I'm not a big fan of having to do this setup/teardown maintenance, but that's an unfortunate side effect of having an API based on static methods (or Singletons for that matter). What I do like about this test is it does not use JNDI - that's good because (a) it'll run fast, and (b) the unit test should only be testing the business logic in doSomeLegacyStuff() method anyway, not testing the actual data source. (By the way, this assumes the test class is in the same package as MyLegacyClass.)
public class MyLegacyClassTest extends TestCase {
private MockStrategy mockStrategy = new MockStrategy();
protected void setUp() throws Exception {
MyLegacyClass.setStrategy(mockStrategy);
}
protected void tearDown() throws Exception {
// TODO, reset original strategy on MyLegacyClass...
}
public void testDoSomeLegacyStuff() {
MyLegacyClass.doSomeLegacyStuff(..);
assertTrue(..);
}
static class MockStrategy implements Strategy{
public SomeLegacyClass doSomeStuff(SomeOtherLegacyClass legacyObj) {
// mock behavior however you want, record state however
// you'd like for test asserts. Good frameworks like Mockito exist
// to help create mocks
}
}
}