测试和继承问题

时间:2010-12-08 19:48:20

标签: java unit-testing inheritance junit

想象一下,你有一个应用程序,你想对它进行单元测试和功能测试(不是很难想象)。你可能有一个抽象类,我们称之为AbstractTestClass,你的所有单元测试都会从中扩展。

AbstractTestClass看起来像这样(使用JUnit 4):

class AbstractTestClass {
    boolean setupDone = false;

    @Before
    public void before() {
        if(!setupDone) {
            // insert data in db
            setupDone = true;
        }
    }
}

这就是我正在努力的方向。我有另一个测试Web界面的抽象类:

class AbstractWebTestClass extends WebTestCase {
    boolean setupDone = false;

    @Before
    public void before() {
        if(!setupDone) {
            // here, make a call to AbstractTestClass.before()
            // init the interfaces
            setupDone = true;
        }
        // do some more thing
    }
}

除了扩展WebTestCase之外,它几乎是同一个类。这种设计可以让我在单元测试时获得与测试接口时相同的数据。

通常,在处理此类问题时,您应该优先考虑组合而不是继承或使用策略模式。

不幸的是,我不喜欢在这个特定场景中支持组合而不是继承的想法,我不知道如何使用策略模式,可能存在设计缺陷,我无法看到溶液

我如何设计这个架构以实现我的目标。

3 个答案:

答案 0 :(得分:2)

我将通过以下方式实现此目的:

class Example {

class LazyInitStrategy implements Runnable {
    private final Runnable operation;
    private boolean done = false;

    LazyInitStrategy(Runnable operation) {
        this.operation = operation;
    }

    @Override
    public void run() {
        if (!done) {
            operation.run();
            done = true;
        }
    }
}

private final class AbstractInit implements Runnable {
    public void run() {
        // insert data in db
    }
}

private final class AbstractWebInit implements Runnable {
    public void run() {
        // here, make a call to AbstractTestClass.before() init the interfaces
    }
}

class AbstractTestClass {

    final LazyInitStrategy setup = new LazyInitStrategy(new AbstractInit());

    @Before
    public void before() {
        setup.run();
        // do some more thing
    }
}

class AbstractWebTestClass extends WebTestCase {

    final LazyInitStrategy setupInfo = new LazyInitStrategy(new AbstractWebInit());

    @Before
    public void before() {
        setupInfo.run();
        // do some more thing
    }
}

}

当然这是一个非常简单的解决方案,但它应该消除if / else逻辑重复,以检查设置是否已完成。使用Runnable是可选的,我这样做是为了演示目的,在阅读世界中你可能会使用另一个界面。

答案 1 :(得分:0)

要完成的重要事情不是重复代码。在这种情况下,我会创建一个

MyScenarioTestUtil

类上有一堆静态方法,可以根据需要设置数据。您将从设置中调用实用程序方法。这样你就可以将所有代码保存在一个地方。

它真的只是与使用合成语言的语义差异......

答案 2 :(得分:0)

我认为一般来说设计是错误的。你根本不应该在单元测试中使用继承。测试应该是孤立的,非常简单。很多时候,就像你的情况一样,有必要准备一些补充对象,这将有助于测试方法来完成他们的工作。在这种情况下,您应该定义此类对象的构建器,并将它们放在测试用例之外的某处。

例如:

public void testMethodThatNeedsSomePreparedObjects() {
  Foo foo = new FooBuilder()
    .withFile("some-text.txt")
    .withNumber(123)
    .build();
  // now we are testing class Bar, using object of class Foo
  Bar bar = new Bar(foo);
}

因此,您需要在其他地方定义FooBuilder,并且此类将执行您现在尝试使用状态模式或继承执行的所有工作。在处理单元测试时,两者都是错误的。