Tdd

什么时候不用测试驱动开发(TDD)

我什么时候不使用TDD?

Alex Bunardzic一直是有关TDD及其反对者的 Twitter 话题中的一员。他的担忧之一是TDD的支持者同意TDD并不总是合适的,但没有说什么时候不用TDD。让我们探索一下。

亚历克斯的担忧似乎在于他正试图让组织中的人员使用TDD,其中许多人提出了异议。这些异议之一是,甚至专家都说他们并不总是使用TDD,所以我们为什么要在这里使用TDD。

现在,如果您接受销售培训^1^,那么您将要教的一件事是如何处理异议。第一项也是最强大的技术是忽略它们。在销售中,您可能会继续提出反对意见,这就是为什么我们很多人讨厌被出售的原因之一。

我没有卖任何东西,但似乎Alex负责在他的公司中销售TDD,所以我们可能有不同的担忧。我在写和讲授思想上的关注是可以理解的。我很乐意将决定权交给听众。如果我每月都有这么多TDD销售的配额,我可能会有所不同。

尽管如此,我确实知道有些情况下我通常不使用TDD,并且我或多或少乐于谈论它们。或多或少是因为TDD主题似乎不断地深入我的灵魂。无论如何,这里是:

我什么时候不用TDD?

让我数一数:我有时不用TDD的…

  1. 当手头没有合适的TDD工具时;
  2. 当我不知道如何测试某事时;
  3. 当输出本质上是可见时(可视化);
  4. 当程序是一个简单的,会扔掉的。

让我们通过示例进一步探讨其中的每一个情况。

当没有像样的测试工具可以立即使用时,我通常不用TDD。

一个例子是我iPad上的Codea Lua。它没有附带TDD工具,而且很长一段时间没有可用的工具。我很喜欢写一个玩玩,因为在Lua中反思很有趣,但从未真正得出我喜欢的东西。

然后出现了CodeaUnit,它工作得非常好,我最近在示例TDD会话中使用了它。但是请参阅以下部分。

另一个示例是Second Life的脚本语言LSL。该语言非常初级,不包含反射功能,这在您尝试生成一个体面的TDD框架时非常重要。如果没有可用的工具,则我用TDD的频率将比理想情况低。

***但是请注意:***缺少一个不错的工具并不是不使用TDD的很好理由。通常,我在Lua或LSL上的开发所花的时间要比遵循TDD学科所需的时间长。我怎么知道?我对使用TDD和不使用TDD时会发生的事情非常有经验,因此我很容易认识到缺少测试会伤害我的情况。

最好的迹象是调试会话需要更多的时间。这总是表明更多测试时我‘会做得更好。

如果工具不易使用,您是否应该考虑不使用TDD?

我认为这不是很好的理由。几乎可以肯定的是,无论您使用哪种语言,都可以使用一个很好的TDD工具。对我来说,如果是只写一些小小的一次性程序的人,寻找和学习该工具的投资可能不值得。您正在专业地工作。对于您来说,投资可能是值得的。

很可能,这对我来说是值得的。在没有TDD的情况下工作会使我更经常地进入调试模式。即使对于我的小型项目,TDD的价值也可能存在。我将自己不这样做的原因归咎于懒惰,说实话而不是出于智慧。

当输出本质上是可见(可视化)时,我通常不进行测试。

在Codea / Lua中,人们经常编写一些代码在屏幕上绘制运动对象。在《第二人生》中,我经常编写脚本来在虚拟世界中移动事物。尽管这些脚本中的某些部分可能会从TDD中受益,但总会有一些-其主要功能使我不知道如何有效地使用TDD。

让我们举两个例子。

想象一下,我想在iPad屏幕上绘制一个蒸汽引擎。该图片的一部分将是引擎驱动轮,该驱动轮会随着火车的移动而旋转。推杆安装在该轮的半径中间附近。该推杆的轮端绕转^2^左右。该杆的另一端在连接到蒸汽活塞的另一根水平杆的推动下水平地前后移动,该水平杆只是来回运动。

我们的任务是在轮子旋转时针对每个角度计算推杆的位置。为了弄清楚该如何做,我绘制了一些草图并做了一些几何处理(通常使用直角三角形),直到我弄清楚了在每个方向盘上的远端在哪个位置。

显然,当车轮为零时,推杆完全远离车轮,其端点为l + r,其中r为推杆圆的半径,l为杆的长度,假设车轮位于零位置。

当车轮处于180度时,终点将在l-r处。当车轮位于90或270时,终点将为…sqrt(l ^ 2-r ^ 2)。同时,如果角度为θ,则起点为<1,0> rotBy(θ)。

大概。多一点的几何使我相信终点是sqrt(l*l - y*y) - x,其中x和y是起点的相对坐标。

也许,有一种更好的方法来计算终点。它一定是某种 sin或cos (正弦或余弦)功能或类似的东西。但是这种方法很好用,因为我们有能力在两点之间画一条线。

所以我只是编写了代码,看起来像这样,没有进行大量清理:

-- Loco

function setup()
    theta = 0 -- degrees
    deltaTheta = 1
    origin = vec2(600,600)
    radius = 200
    rodRadius = radius/2
    rodLength = 500
end

function draw()
    background(40, 40, 50)
    strokeWidth(5)
    drawWheel()
    drawRod()
    theta = theta + deltaTheta

end

function radians(angleInDegrees)
    return angleInDegrees*math.pi/180
end

function drawRod()
    pushMatrix()
    local rodOrigin = vec2(0,rodRadius):rotate(radians(theta))
    local x = rodOrigin.x
    local y = rodOrigin.y
    translate(origin.x, origin.y)
    ellipse(rodOrigin.x, rodOrigin.y, 15)
    local rodEnd = math.sqrt(rodLength*rodLength - y*y) + x
    line(x,y, rodEnd,0)
    -- local dist = vec2(x,y):dist(vec2(rodEnd,0))
    -- print(dist)
    popMatrix()
end

function drawWheel()
    pushMatrix()
    noFill()
    translate(origin.x, origin.y)
    ellipse(0,0,2*radius)
    rotate(theta)
    line(-radius,0,radius,0)
    line(0,radius, 0, -radius)
    popMatrix()
end

这是运行时的视频,请点击这里。