2008-10-30 60 views
8

静态字段我有以下的遗留代码:重构静态方法/试验

public class MyLegacyClass 
{ 
    private static final String jndiName = "java:comp/env/jdbc/LegacyDataSource" 

    public static SomeLegacyClass doSomeLegacyStuff(SomeOtherLegacyClass legacyObj) 
    { 
     // do stuff using jndiName 
    } 
} 

这个类是在J2EE容器的工作。

现在我想测试容器外的类。

什么是最佳策略? 重构基本上是允许的。

允许访问LegacyDataSource(测试不必是“纯”单元测试)。

编辑:引入额外的运行时框架是不允许的。

+0

我根据你的新限制更新了我的答案。我们实际上有一个系统必须解决同样的问题。 – Robin 2008-10-30 13:41:23

回答

7

只是为了让一个@策略模式更具体的罗宾的建议:(请注意,你原来的问题的公共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 
    } 
    } 
} 
2

重构要使用依赖注入的代码。然后用你喜欢的DI框架(Spring,Guice,...)来注入你的资源。这将使运行时在资源对象和策略之间轻松切换。

在这种情况下,您可以注入数据源。

编辑:基于您的新限制,您可以通过使用战略模式在运行时设置您的数据源来完成同样的事情。您可能只需使用属性文件来区分要创建和提供数据源的策略。这不需要新的框架,只需手动编码相同的基本功能即可。我们在ServiceLocator中使用这个确切的想法来在Java EE容器之外进行测试时提供模拟数据源。

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); 

或类似的东西,希望对你有所帮助。

祝你好运!