当生产功能可以有数百万个测试用例时,TDD如何工作?

The*_*ght 26 c# asp.net algorithm tdd primes

在TDD中,您选择一个测试用例并实现该测试用例然后您编写足够的生产代码以便测试通过,重构代码并再次选择一个新的测试用例并继续循环.

我在这个过程中遇到的问题是TDD说你只编写了足够的代码来传递你刚写的测试.我所指的确切地说,如果一个方法可以有100万个测试用例,你能做什么?!显然没有写100万个测试用例?!

让我通过下面的例子更清楚地解释一下我的意思:

 internal static List<long> GetPrimeFactors(ulong number)
        {
            var result = new List<ulong>();

            while (number % 2 == 0)
            {
                result.Add(2);
                number = number / 2;
            }

            var divisor = 3;

            while (divisor <= number)
            {
                if (number % divisor == 0)
                {
                    result.Add(divisor);
                    number = number / divisor;
                }
                else
                {
                    divisor += 2;
                }
            }

            return result;
        }
Run Code Online (Sandbox Code Playgroud)

上面的代码返回给定数字的所有素数因子.ulong有64位,这意味着它可以接受0到18,446,744,073,709,551,615之间的值!

那么,当生产功能可以有数百万个测试用例时,TDD如何工作?!

我的意思是有多少测试用例可以编写,所以我可以说我使用TDD来实现这个生产代码?

TDD中的这个概念说你应该只编写足够的代码来通过测试,这对我来说似乎是错误的,如上面的例子所示?

什么时候足够了?

我自己的想法是,我只挑选一些测试用例,例如高频段,低频段和更多例如5个测试用例,但这不是TDD,是吗?

非常感谢您对此示例的TDD想法.

Mat*_*ias 31

这是一个有趣的问题,与认识论中的可证伪性概念有关.通过单元测试,您并不是真的想要证明系统有效; 你正在构建实验,如果它们失败,将证明系统不能以符合你的期望/信念的方式工作.如果您的测试通过,您不知道您的系统是否正常工作,因为您可能已经忘记了一些未经测试的边缘情况; 你知道的是,截至目前,你没有理由相信你的系统有问题.

科学史上的经典例子是"所有天鹅都是白色的"这个问题.无论你发现多少只不同的白天鹅,你都不能说假设"所有天鹅都是白色的"是正确的.另一方面,带给我一只黑天鹅,我知道这个假设是不正确的.

沿着这些方向进行了良好的TDD单元测试; 如果它通过,它不会告诉你一切都是正确的,但如果它失败了,它会告诉你你的假设是不正确的.在那个框架中,对每个数字的测试都没有那么有价值:一个案例就足够了,因为如果它不适用于那个案例,你就会知道出了什么问题.

当问题是有趣的是,虽然不像天鹅,你真的不能每次天鹅枚举世界,和他们所有的未来的孩子和他们的父母,你可以列举每一个整数,这是一个有限集,并验证每种可能的情况.此外,一个程序在很多方面更接近数学而不是物理,在某些情况下,你也可以真实地验证一个陈述是否正确 - 但在我看来,这种类型的验证不是TDD所追求的.TDD正在进行良好的实验,旨在捕捉可能的失败案例,而不是证明某些事情是真的.


Dom*_*nic 19

你忘记了第三步:

  1. 红色
  2. 绿色
  3. 重构

编写测试用例会让你变红.

编写足够的代码来使这些测试用例通过可以让你变成绿色.

将代码推广到不仅仅是你编写的测试用例,而不是破坏它们中的任何一个,都是重构.

  • 另一个观点:应用于TDD的"代码覆盖"概念不是覆盖所有可能的输入值,而是覆盖所有可能的分支逻辑路径.如果您的测试用例涵盖所有可能的分支逻辑路径,那么即使您没有对所有可能的输入进行测试,也可以对所有代码进行测试. (4认同)
  • 重构意味着对不改变其外部输出的代码进行更改.在TDD的上下文中,这意味着对代码进行更改,无论是否通过测试都不会改变.再次,TDD编写足够的代码以通过测试的概念是TDD的步骤1-2; 你完全无视第3步. (2认同)

Car*_*ter 11

您似乎将TDD视为黑盒测试.不是.如果是黑盒测试,只有完整的(数百万个测试用例)测试集会满足你,因为任何给定的情况都可能未经测试,因此黑盒子中的恶魔将能够逃脱作弊.

但是你的代码中的黑盒子里不是恶魔.这是你,在一个白色的盒子里.你知道你是否在作弊.Fake It Til You Make的做法与TDD密切相关,有时与它混淆.是的,你编写虚假的实现来满足早期的测试用例 - 但你知道你是在假装它.你也知道你什么时候停止伪装它.你知道什么时候你有一个真正的实现,并且你已经通过渐进式迭代和测试驱动来实现.

所以你的问题确实是错误的.对于TDD,您需要编写足够的测试用例来推动解决方案的完成和正确性; 您不需要为每个可能的输入集合设置测试用例.


Yah*_*hia 6

从我的POV开始,重构步骤似乎没有发生在这段代码上......

在我的书中,TDD并不意味着为每个可能的输入/输出参数的每个可能的排列编写测试用例......

但要编写所有需要的测试用例,以确保它完成指定的操作,即对于这种方法,所有边界情况加上一个测试,该测试从包含已知正确结果的数字的列表中随机选取一个数字.如果需要,您可以随时扩展此列表以使测试更加彻底......

如果你不把常识抛到窗外,TDD只适用于现实世界......

至于

只写足够的代码来通过测试

在TDD中,这指的是"非作弊程序员"......如果你有一个或多个"作弊程序员",例如只是将测试用例的"正确结果"硬编码到方法中,我怀疑你的问题就更大了手比TDD ......

BTW"Testcase构建"是你练习得越多越好的东西 - 没有任何书籍/指南可以告诉你哪些测试用例最适合任何给定的情况......在构建测试用例时体验会有很大的回报. ..