Frage

Ich habe folgenden Legacy-Code:

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

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

Diese Klasse arbeitet in einem J2EE-Container.

Nun möchte Ich mag die Klasse außerhalb des Behälters testen.

Was ist die beste Strategie? Refactoring ist grundsätzlich erlaubt.

Zugriff auf der LegacyDataSource erlaubt (der Test nicht über einen "reiner" Unit-Test sein).

EDIT:. Die Einführung zusätzlicher Laufzeit-Frameworks ist nicht erlaubt

War es hilfreich?

Lösung

Just machen @ Robin Vorschlag einer Strategie Muster konkreter: (. Beachten Sie, dass die öffentliche API von Ihrer ursprünglichen Frage bleibt unverändert)

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
  }
}

... und JUnit-Test. Ich bin kein großer Fan von dieser Setup / Teardown Wartung zu tun haben, aber das ist eine unglückliche Nebenwirkung eine API auf statische Methoden basieren (oder Singletons für diese Angelegenheit). Was I tun wie etwa dieser Test ist es nicht JNDI Anspruch nimmt - das ist gut, weil (a) es schnell laufen werden, und (b) sollte das Gerät Test nur in doSomeLegacyStuff die Geschäftslogik zu testen werden ( ) Verfahren wie auch immer, nicht die tatsächliche Datenquelle testen. (By the way, diese übernimmt die Testklasse im selben Paket wie MyLegacyClass ist.)

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
    }
  }
}

Andere Tipps

Umgestalten den Code Dependency Injection zu verwenden. Dann nutzen Sie DI Rahmen bevorzugt (Spring, Guice, ...) Ihre Ressourcen zu injizieren. Das macht es einfach, zwischen Ressourcenobjekten und Strategien zur Laufzeit wechseln.

In diesem Fall können Sie Ihre Datenquelle injizieren.

EDIT: Basierend auf den neue Einschränkung, können Sie das Gleiche erreichen, indem ein Strategie-Muster mit Ihrer Datenquelle zur Laufzeit zu setzen. Sie können sich wahrscheinlich verwenden nur eine Properties-Datei, die Strategie zu unterscheiden, die Datenquelle zu erstellen und zu liefern. Dies würde keine neuen Rahmen benötigen, würden Sie nur die Hand sein, die gleiche grundlegende Funktionalität Codierung. Wir nutzten diese genaue Idee, mit einem Servicelocator eine Mock-Datenquelle zu liefern, wenn sie außerhalb der Java EE Container testen.

Ich denke, dass die beste Lösung hier binden, dass JNDI zu einem lokalen

Das Vermächtnis-Code wird mit dem jndiName wie folgt aus:

DataSource datasource = (DataSource)initialContext.lookup(DATASOURCE_CONTEXT);

So, hier die Lösung binden, wird eine lokale (oder was auch immer Sie haben, um Daten zu testen) in eine JNDI wie folgt aus:

  BasicDataSource dataSource = new BasicDataSource();
  dataSource.setDriverClassName(System.getProperty("driverClassName"));
  dataSource.setUser("username");
  dataSource.setPassword("password");
  dataSource.setServerName("localhost");
  dataSource.setPort(3306);
  dataSource.setDatabaseName("databasename");

Und dann der Bindung:

Context context = new InitialContext();
context.bind("java:comp/env/jdbc/LegacyDataSource",datasource); 

oder etwas ähnliches, die Hoffnung, das Ihnen hilft.

Viel Glück!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top