如何正确使用TDD实现数值方法?

Jad*_*ias 10 tdd numerical

我正在尝试使用测试驱动开发来实现我的信号处理库.但我有点怀疑:假设我正在尝试实现一个正弦方法(我不是):

  1. 写测试(伪代码)

    assertEqual(0, sine(0))
    
    Run Code Online (Sandbox Code Playgroud)
  2. 编写第一个实现

    function sine(radians)
        return 0
    
    Run Code Online (Sandbox Code Playgroud)
  3. 第二次测试

    assertEqual(1, sine(pi))
    
    Run Code Online (Sandbox Code Playgroud)

在这一点上,我应该:

  1. 实现一个适用于pi和其他值的智能代码,或者
  2. 实现最适合0和pi的最愚蠢的代码?

如果您选择第二个选项,我什么时候可以跳转到第一个选项?我最终还是要这样做......

S.L*_*ott 9

在这一点上,我应该:

  1. 实现在两个简单测试之外工作的真实代码?

  2. 实现更多最愚蠢的代码,只适用于两个简单的测试?

都不是.我不确定你从哪里得到"一次只写一个测试"的方法,但这肯定是一个缓慢的方法.

关键是要编写清晰的测试并使用明确的测试来设计您的程序.

因此,编写足够的测试来实际验证正弦函数.两项测试显然不足.

在连续函数的情况下,您必须最终提供已知良好值的表.干嘛要等?

但是,测试连续函数存在一些问题.你不能遵循愚蠢的TDD程序.

您无法测试0到2*pi之间的所有浮点值.您无法测试一些随机值.

在连续功能的情况下,"严格,不假思索的TDD"不起作用.这里的问题是你知道你的正弦函数实现将基于一堆对称性.您必须根据您正在使用的那些对称规则进行测试.虫子隐藏在裂缝和角落里.边缘情况和角落情况是实施的一部分,如果你不假思索地遵循TDD,你无法测试.

但是,对于连续函数,您必须测试实现的边缘和边角情况.

这并不意味着TDD被破坏或不足.它说,如果不考虑一下你真正的目标是什么,那么对"先试验"的盲目奉献是行不通的.


Yis*_*hai 5

在严格的婴儿步TDD中,您可以实现哑方法以恢复绿色,然后重构哑代码中固有的重复(测试输入值是测试和代码之间的一种重复)通过生成一个真正的算法.使用这种算法感受TDD的难点在于你的验收测试真的就在你旁边(表格S. Lott建议),所以你总是要密切注意它们.在更典型的TDD中,单元与整体分离得足够多,接受测试不能直接插入到那里,因此您不会开始考虑测试所有场景,因为所有场景都不明显.

通常,在一两个案例之后,您可能会有一个真实的算法.关于TDD的重要一点是它驱动设计而不是算法.一旦有足够的案例来满足设计需求,TDD中的值就会显着下降.然后测试更多地转换为覆盖角落情况,以确保您的算法在您能想到的所有方面都是正确的.因此,如果您对如何构建算法有信心,那就去吧.你所讨论的婴儿步骤的种类只有在你不确定时才适用.通过采取这些步骤,您可以开始构建代码必须涵盖的范围,即使您的实现尚未实现.但正如我所说,当你不确定如何构建算法时,这更有用.


rwo*_*ong 5

编写验证身份的测试.

对于sin(x)示例,请考虑双角公式和半角公式.

打开信号处理教科书.查找相关章节并将这些定理/推论中的每一个实现为适用于您的函数的测试代码.对于大多数信号处理功能,必须坚持输入和输出的标识.编写验证这些身份的测试,无论这些输入是什么.

然后考虑一下输入.

  • 将实施过程分为不同的阶段.每个阶段都应该有一个目标.每个阶段的测试将是验证目标.(注1)
    1. 第一阶段的目标是"大致正确".对于sin(x)示例,这就像使用二进制搜索和一些数学身份的天真实现.
    2. 第二阶段的目标是"足够准确".您将尝试不同的方法来计算相同的功能,并查看哪一个获得更好的结果.
    3. 第三阶段的目标是"高效".

(注1)使其正常工作,使其正确,快速,便宜. - 归功于Alan Kay