我想开始对我们的应用程序进行单元测试,因为我相信这是与测试建立良好关系的第一步,并允许我分支到其他形式的测试,最有趣的是带有Cucumber的BDD。
我们目前使用Codesmith生成所有Base类,它们完全基于数据库中的表。我很好奇使用这些Base类生成测试用例的好处?这是不好的测试实践吗?
这引出了我的帖子的终极问题。使用单元测试时我们测试什么?
我们是否测试了我们想知道的例子?还是我们测试我们不想要的例子?
他们的方法可能有多种失败方式和多种成功方式,我们怎么知道何时停止?
以Summing函数为例。给它1,2并且在唯一的单元测试中期望3 ..我们怎么知道5,6不回来35?
问题回顾
答案 0 :(得分:7)
从您的要求开始,编写测试预期行为的测试。从那时起,您测试的其他场景可以由您的日程表驱动,也可能由您认识到特别高风险的非成功场景。
您可能会考虑编写非成功测试,仅用于响应您(或您的用户)发现的缺陷(想法是您在实际修复缺陷之前编写测试缺陷修复的测试,以便您的测试失败如果在将来的开发中将该缺陷重新引入您的代码中。)
答案 1 :(得分:6)
单元测试的目的是让你自信(但只有在特殊情况下才能确定),公共方法的实际行为与预期的行为相匹配。因此,如果您有一个班级Adder
class Adder { public int Add(int x, int y) { return x + y; } }
和相应的单元测试
[Test]
public void Add_returns_that_one_plus_two_is_three() {
Adder a = new Adder();
int result = a.Add(1, 2);
Assert.AreEqual(3, result);
}
然后这会给你一些(但不是100%)的信心,即测试中的方法表现得恰当。它还为您提供了一些防止在重构时破坏代码的防御。
使用单元测试时我们测试什么?
公共方法对预期(或指定)行为的实际行为。
我们是否测试了我们想知道的示例?
是的,获得对方法正确性的信心的一种方法是获取具有已知预期输出的输入,在输入上执行公共方法并将实际输出与预期输出进行比较。
答案 2 :(得分:4)
测试什么:一切都出错了。
当您发现错误时,请在修复代码之前之前针对错误行为编写测试。然后,当代码正常工作时,测试将通过,您将在您的工具库中进行另一项测试。
答案 3 :(得分:3)
1)首先,我建议您测试应用的核心逻辑。
2)然后,在vs中使用代码覆盖工具来查看是否在测试中使用了所有代码(if-else的所有分支,都调用了大小写条件)。 这是关于测试1 + 2 = 3,5 + 6 = 35的问题的某种答案:当代码被覆盖时,您可以通过进一步的实验感到安全。
3)覆盖80-90%的代码是一种很好的做法:其余的工作通常都是无效的:getters-setters,1行异常处理等。
4)了解关注点的分离。
5)生成单元测试 - 尝试一下,你会发现,你可以保存一行漂亮的代码来手动编写它们。我更喜欢使用vs生成文件,然后自己编写其余的TestMethods。
答案 4 :(得分:2)
你对你所在的地方进行单元测试
因此,在您的示例中,测试生成的类没有多大意义。改为测试发电机。
首先测试主要用例(测试功能的设计)是一种很好的做法。然后测试主要错误情况。然后你为角落情况(即下限和上限)编写测试。通常很难产生不常见的错误情况,因此对它们进行单元测试是没有意义的。
如果您需要验证大量参数集,请使用数据驱动的测试。
你测试的事情是努力与回归的关系,所以它实际上取决于个别项目。通常,您尝试遵循80/20规则,但可能存在需要更多测试覆盖率的应用程序,因为失败会产生非常严重的后果。
如果使用测试驱动方法(TDD),则可以大大减少编写测试所需的时间。那是因为没有考虑可测试性的代码要困难得多,有时几乎无法测试。但由于生活中没有任何东西是免费的,因此使用TDD开发的代码本身往往更加复杂。
答案 5 :(得分:1)
我也开始更一致地使用单元测试的过程,我发现单元测试中的最大任务是构建我的代码以支持测试。当我开始考虑如何编写测试时,很明显哪些类已经过度耦合,以至于“单元”的复杂性使定义测试变得困难。在编写测试时,我花了很多或者更多的时间来重构我的代码。一旦可测试单元之间的界限变得更加清晰,从何处开始测试的问题就会自行解决;从你最小的孤立依赖(或者至少是你担心的那些)开始,然后继续努力。
答案 6 :(得分:1)
我测试了三个基本事件: min,max,介于最小和最大之间
适当的两个极端:低于最低,高于最高
有明显的例外(例如某些代码可能没有最小值或最大值),但我发现对这些事件进行单元测试是一个良好的开端,可以捕获代码中的大多数“常见”问题。