7

我有以下结构:

class Bar{
  ....
  protected void restore(){
    ....
  }

  ....
}

此类扩展Foo如下:

class Foo extends Bar{
    ....

    @Override
    public void restore(){  //valid override
        super.restore();

        ....
    }
}

在我的 jUnit 测试中,我想测试何时foo.restore()调用,super.restore()随后调用。因此,下面是我的 jUnit 测试方法:

class FooTest{
  @Tested
  Foo _foo;

  @Test
  void testRestore(final Bar bar){

    new Expectations(){{
      bar.restore(); times = 1; // Error! bar.restore() not visible
    }};

    Deencapsulation.invoke(_foo,"restore");
  }
}

不幸的是,我的测试无法编译。原因是 1)restore()父级是protected和 2)FooTestFoo一起存在于一个单独的项目(因此是文件夹)与Bar.

反正有没有达到预期的测试?我已经检查了jMockit 教程(在过去几个月中多次)并且没有看到类似的测试(在 Google 上搜索也是如此)。


更新

在回复的帮助下,我了解到强制调用子类super不是最佳实践,但这不是我的实现,我仍然需要对其进行测试。我仍在寻找一种方法来强制执行我的 jUnit 测试以检查对父级的调用是否正在发生。

4

3 回答 3

4

所以基本上你是在尝试执行调用超级的合同并尝试允许子类化?我认为这并不容易,因为动态调度会隐藏 Java 中的行为。我不认为 Mocking 会抓住这一点。

确保调用 super 的一种方法是将 super 和扩展分解为 2 种方法,例如

class Foo {
  public final void restore() {
    //parent code...
    doRestore();
  }

  protected void doRestore() {
    //empty base implementation
  }
}

class Bar extends Foo {
    protected void doRestore() {
      //do my subclass specific restore stuff here
    } 
}
于 2013-01-11T20:50:59.407 回答
2

以下测试应该有效:

public class FooTest
{
    @Tested Foo _foo;

    @Test
    void restoreInFooCallsSuper(@Mocked final Bar bar)
    {
        new Expectations() {{
            invoke(bar, "restore");
        }};

        _foo.restore();
    }
}
于 2013-01-15T15:03:45.777 回答
1

super.restore()应该做一些有用的事情不是吗?一些具体的逻辑。在您的测试中,只需测试调用super.restore()发生的结果。

另一种研究方法如下。在执行任何操作之前,在子类中实现一个assert确保超级正确地完成其工作。这是一个更强大的检查,并且作为 Meyer 的合同设计范式的一部分而广为人知。super.restore()在这种情况下,子类只是在执行之前检查实现的后置条件是否成立,并且通过使用assert您知道它将在单元测试期间以及在应用程序的测试集成运行期间失败,例如

class Foo extends Bar{
    ....

    @Override
    public void restore(){  //valid override
        super.restore();
        assert super_restore_worked_ok_condition : "restore post-condition failed";

        ....
    }
}
于 2013-01-11T20:47:13.403 回答