我观看了几个关于测试驱动开发的视频,我大多理解它。但事实上,在我看过的所有视频中,这些方法都是如此静态。所以在我的例子中,怪物必须总是有100个生命值并且攻击者有70个。那么当你只能覆盖一个案例时,这与测试有什么关系呢?
示例测试:
monster = Monster.new
monster.hitpoints = 100
hero = Hero.new
hero.strength = 70
hero.attack(monster)
monster.hitpoints.should == 30
以下是代码:
class Monster
attr_accessor :hitpoints
end
class Hero
attr_accessor :strength
def attack(monster)
monster.hitpoints -= strength
end
end
答案 0 :(得分:2)
测试方法是静态的,因为您正在观看视频。他们为您提供测试框架的概念和语法,不一定是" best"或"现实世界"做法。
在您的示例中,您将要检查哪些边缘情况,这将导致非常相似的外观测试。因此,考虑一下常用代码。
def test_post_attack_hitpoints(initial, strength, expected):
monster = Monster.new
monster.hitpoints = initial
hero = Hero.new
hero.strength = strength
hero.attack(monster)
monster.hitpoints.should == expected
end
test_post_attack_hitpoints(100, 70, 30)
test_post_attack_hitpoints(100, 110, -10) # do you actually expect -10?
test_post_attack_hitpoints(100, -10, 110) # can a hero's strength go negative? Should that heal the monster?
一般来说,视频和教程将教你绝对最低限度,让你做一些事情。学习做事好是经验问题。首先要学习其他人的经历。看看在备受推崇的开源项目中如何构建单元测试。我不一定能指出你在Ruby世界中的好例子,但Rails的测试套件肯定已经广泛运用,可能是一个合理的起点。看看他们如何组织事情。
然后从自己的经验中学习。写一堆单元测试。什么效果好,什么似乎愚蠢?找到一种能够解决您自己(或您的团队)需求的风格并做到这一点。
我现在要离开我的肥皂盒了。
答案 1 :(得分:2)
完全故意这样做。单元测试的一个基本特征是它们必须是可预测的,并且每次运行时都会得到相同的结果。为什么?因为您希望代码完全可预测且测试结果完全一致。每个运行测试的开发人员都应该得到完全相同的结果,无论何时,如何或在什么环境中,他们都可以以可预测的方式修复/重构/开发。
每次测试(或应该)用于测试一个特定情况或案例。在你的情况下,攻击怪物的英雄会产生一定程度的伤害。你是对的,因为特定的测试只会覆盖一个案例,这样做是正确的。它正在测试已经设计的特定情况。它的好处是这些案例应该具有足够的代表性,以适应大多数情况。
例如,这是涵盖正常攻击情况的典型测试。例如,第二次测试将给英雄带来50的攻击和怪物只有30个生命值,并断言怪物有0个生命值并且变得死亡。还有一个人可以为怪物提供一个盾牌,并且还可以减少伤害。这个想法是创造具有代表性的案例。一个不太有用的测试的例子是添加另一个具有英雄50攻击和怪物200次命中,特别是它没有做任何概念上与你的例子不同的事情,并且很可能都会通过或两者都失败。
边缘情况也很有用。如果怪物的生命值和英雄的攻击是相同的,会发生什么?它应该杀死还是几乎死了?另一个有趣的案例可能是无效输入,应该返回错误。
但一般的想法是,它们是静态的是使它们可靠和可重复的特征。一个测试,一个特别的测试,不再是。
另请看这里:What are the downsides using random values in Unit Testing?
答案 2 :(得分:1)
所有测试都是这样的,不仅仅是TDD测试。根本问题是潜在测试输入的数量巨大。想象一下,你必须测试一个采用32位长的两个整数的方法,你可以每秒编写和运行1000个测试用例。您需要多长时间来测试所有可能的输入?猜猜,然后做计算。您可能会感到惊讶的是需要多长时间。测试是选择性的。我们选择了少量的测试用例,我们希望这些测试用例能够在测试中做得非常好,而不需要进行完美的测试。
测试技能的一部分是知道如何选择一组好的测试用例,尽管数量很少,但测试用例也很好。事实上,TDD可以很好地做到这一点,因为它坚持通过执行将使测试通过的最小来实现绿色阶段(通过所有测试)。完成后,您可能会查看代码并发现它不完整。这将建议进一步的测试用例,这对于证明代码更接近完成是必要的。
答案 3 :(得分:1)
我只会在已经很好的答案中添加一两点。
如果您必须手动测试此方法,是否必须通过所有值才能知道它是否有效?当然不是。您将测试“正常路径”和边缘情况,就像neilh在他的回答中所做的那样。这就是你在编写自动单元测试时所做的事情(TDD与否)。
不要将自动单元测试视为数学上详尽的测试。将它们视为一种屏蔽,可以在重构代码时保护您不会破坏任何内容。让它们足够覆盖,以便它们获得你的完全信心(这是非常重要的一点),但不要试图覆盖所有应用程序的可能状态(你不能)。您需要测试所有可能的路径,这是非常不同的。