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-Container 中工作。

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

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

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

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

4

3 回答 3

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 测试。我不太喜欢进行这种设置/拆卸维护,但这是拥有基于静态方法(或单例)的 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
    }
  }
}
于 2008-10-30T15:36:50.697 回答
2

重构代码以使用依赖注入。然后使用您喜欢的 DI 框架(Spring、Guice、...)来注入您的资源。这将使运行时资源对象和策略之间的切换变得容易。

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

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

于 2008-10-30T13:19:49.320 回答
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); 

或者类似的,希望对你有帮助。

祝你好运!

于 2008-10-30T14:05:45.607 回答