我有以下遗留代码:
public class MyLegacyClass
{
private static final String jndiName = "java:comp/env/jdbc/LegacyDataSource"
public static SomeLegacyClass doSomeLegacyStuff(SomeOtherLegacyClass legacyObj)
{
// do stuff using jndiName
}
}
这个类在J2EE-Container中工作。
现在我想测试容器外的类。
最佳策略是什么? 基本上允许重构。
允许访问LegacyDataSource(测试不必是“纯”单元测试)。
编辑:不允许引入其他运行时框架。
答案 0 :(得分:7)
让@ Robin建议更具体的策略模式:(请注意,原始问题的公共API保持不变。)
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
}
}
...和JUnit测试。我不是必须进行这种设置/拆卸维护的忠实粉丝,但这是一个基于静态方法(或Singletons)的API的不幸副作用。我做喜欢这个测试的是它不使用JNDI - 这很好,因为(a)它会快速运行,(b)单元测试应该只测试doSomeLegacyStuff中的业务逻辑( )方法无论如何,不测试实际的数据源。 (顺便说一下,这假设测试类与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
}
}
}
答案 1 :(得分:2)
重构代码以使用依赖注入。然后使用您首选的DI框架(Spring,Guice,...)来注入您的资源。这样可以在运行时轻松切换资源对象和策略。
在这种情况下,您可以注入数据源。
编辑:根据您的新限制,您可以通过使用策略模式在运行时设置数据源来完成相同的任务。您可以只使用属性文件来区分创建和提供数据源的策略。这将不需要新的框架,您只需手动编码相同的基本功能。在Java EE容器外部进行测试时,我们使用ServiceLocator提供了一个模拟数据源。
答案 2 :(得分:1)
我认为这里最好的解决方案是将JNDI绑定到本地
旧版代码正在使用jndiName:
DataSource datasource = (DataSource)initialContext.lookup(DATASOURCE_CONTEXT);
所以,这里的解决方案是将本地(或者你拥有的任何测试数据)绑定到这样的JNDI中:
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(System.getProperty("driverClassName"));
dataSource.setUser("username");
dataSource.setPassword("password");
dataSource.setServerName("localhost");
dataSource.setPort(3306);
dataSource.setDatabaseName("databasename");
然后是绑定:
Context context = new InitialContext();
context.bind("java:comp/env/jdbc/LegacyDataSource",datasource);
或类似的东西,希望能帮到你。
祝你好运!