2

以 tdd 方式实现时,您是断言类的内部还是仅断言其公共 api?

假设我正在实现一个二进制堆。添加对象后,我想断言保留了堆属性。通过反射获得内部数组然后断言其内容是否有意义?IE

    @Test
    public void shouldPreserveHeapProperty() {
        // when
        heap.push(3);
        heap.push(2);
        heap.push(1);

        // then
        assertThat(Reflection.get(heap,"elements"))).contains(3,2,1);//made up Reflection class
    }

或者也许通过它的公共api?但是每个测试都需要多个断言,即

    @Test
    public void shouldPreserveHeapProperty() {
        // when
        heap.push(3);
        heap.push(2);
        heap.push(1);

        // then
        assertThat(heap.pop()).isEqualTo(3);
        assertThat(heap.pop()).isEqualTo(2);
        assertThat(heap.pop()).isEqualTo(1);
    }

更重要的是,您将如何实现并发代码的测试?有时在不访问内部锁的情况下很难模拟死锁或等待。

4

1 回答 1

1

我认为你应该只使用 API。也就是说,您可以使用包私有访问权限来为您的测试代码和友好的类提供对某些不应公开的项目的有限访问权限。

为此,您会发现要测试您的 mutator 方法,您还需要一些 getter 方法来访问对象的重要属性。对于堆栈,您可能只需要 push 和 pop mutators,但对于测试,拥有 size getter 可能很有用。

我发现以这种方式限制自己自然会导致通过合同方法进行编程,这是一件好事。

当你想重构你的类时,访问私有数据的测试很麻烦。您应该能够轻松更改您想要的私人详细信息,但您还必须更改您的测试代码。

您的示例测试尝试检查该类是否保留了堆属性。这不是一项测试可以检查的。heap 属性是对所有 push 和 pop 序列的约束。尝试用一次推送然后一次弹出来完成一个测试用例,另一个用两次推送然后两次弹出来完成测试。它们一起通过归纳证明您的课程对所有序列都是正确的,从而作为一个穷人的证明。

每个测试应该只包含一个断言的想法很常见,但不必要且麻烦。当您重构代码并且存在引入错误的危险时,您希望最大限度地提高检测到这些错误的机会。所以你应该检查你正在测试的 mutatir 的所有后置条件,以及类的所有不变量。这可能是非常多的断言,因此每个测试用例的多个断言是唯一实用的方法。

于 2013-09-11T07:40:05.380 回答