我正在使用multiply()
方法测试字符串乘数类,该方法将2个数字作为输入(作为String
)并返回结果编号(作为String
)
public String multiply(String num1, String num2);
我已完成实现并创建了一个测试类,其中包含以下测试用例,其中包含输入String参数
现在我的问题是:
我想知道“每个”assertEquals()是否应该在它自己的测试方法中?或者,我可以将类似测试用例(如testInvalidArguments())分组以包含涉及无效字符的所有断言,因为它们都会抛出相同的NumberFormatException吗?
如果测试输入值如字符(“a”),我是否需要包含所有方案的测试用例? “a”作为第一个论点 “a”作为第二个论点 “a”和“b”作为2个参数
根据我的理解,这些单元测试的好处是找出用户输入可能失败并导致异常的情况。然后,我们可以为用户提供有意义的消息(要求他们提供有效的输入)而不是异常。那是对的吗?而且,这是唯一的好处吗?
上面提到的11个测试用例是否足够?我错过了什么?我过头了吗?什么时候够了?
从以上几点开始,我是否成功测试了multiply()方法?
答案 0 :(得分:6)
单元测试很棒(在我正在工作的200 KLOC项目中,我有与常规代码一样多的单元测试代码)但是(假设正确的单元测试):
这样想:
认识到这一点非常重要。
除此之外:
然后,当你重构时:
可是:
这是非常基础的,应该是单元测试101.
答案 1 :(得分:5)
1)我认为限制每次测试中断言的数量是个好主意。 JUnit仅报告测试中的第一次失败,因此如果您有多个断言,则可能会屏蔽某些问题。能够看到通过的所有内容和失败的一切更有用。如果你在一次测试中有10 assertEquals
并且第一次测试失败,那么你就不知道另一次测试会发生什么。这些将是调试时的好数据点。
2)是的,您应该包括所有输入的测试。
3)不仅需要测试最终用户输入。您将要为可能失败的任何公共方法编写测试。有一些很好的指导方针,特别是关于吸气剂和制定者,JUnit FAQ。
4)我认为你已经很好地覆盖了它。 (至少我不能想到其他任何东西,但请看#5)。
5)将其提供给一些用户进行测试。他们总能找到我从未想过测试的样本数据。 :)
答案 2 :(得分:4)
1)在测试的粒度(因此易于诊断)和单元测试代码的详细程度之间存在权衡。我个人很高兴采用相对粗粒度的测试方法,特别是一旦测试和测试代码稳定下来。粒度问题仅在测试失败时才相关。 (如果我在多断言测试用例中出现故障,我要么修复第一个失败并重复,要么我根据需要暂时破解测试用例以弄清楚发生了什么。)
2)运用你的常识。根据您对代码编写方式的理解,设计测试以运用所有定性不同的子类。认识到除了最微不足道的情况之外,所有可能的输入都是不可能。
3)单元测试的目的是提供一定程度的保证,即被测方法可以做他们需要做的事情。这意味着什么取决于被测试的代码。例如,如果我是单元测试sort
方法,则验证用户输入无关紧要。
4)报道似乎合理。但是,如果没有详细说明你的课程要求做什么,以及对实际单元测试的检查,就不可能说你是否已经涵盖了所有内容。例如,您的方法应该处理前导/尾随空格字符,带小数点的数字,数字如“123,456”,使用非拉丁数字表示的数字,基数42中的数字?
5)定义“成功测试”。如果你的意思是,我的测试证明代码没有错误,那么答案肯定是“不”。除非单元测试列举了每个可能的输入,否则它们不能构成正确性的证明。 (在某些情况下,甚至不测试所有输入就足够了。)
除了最微不足道的案例外,测试无法证明缺少错误。唯一可以证明的是存在错误。如果你需要证明一个程序没有错误,你需要采用“正式方法”;即将正式定理证明技术应用于您的计划。
而且,正如另一个答案所指出的那样,你需要把它交给真正的用户,看看他们可能会以意外输入的方式提出什么。换句话说......所声明的或推断的用户要求是否实际完整且有效。
答案 3 :(得分:2)
1)最好让你的测试保持小而专注。这样,当测试失败时,很清楚测试失败的原因。这通常会导致每次测试单个断言,但并非总是如此。
但是,您可能希望查看JUnit 4.4 Theories(请参阅JUnit 4.4 release notes和this blog post)或JUnit,而不是为每个“无效方案”手动编写测试。 Parameterized测试运行员。
参数化测试和理论非常适合像这样的“计算”方法。另外,为了保持井井有条,我可以制作两个测试类,一个用于“好”输入,一个用于“坏”输入。
2)您只需要包含您认为最有可能暴露代码中任何错误的测试用例,而不是所有输入的所有可能组合(这在WizardOfOdds的评论中指出是不可能的)。你提出的三组是好的,但我可能不会测试超过这三组。但是,使用理论或参数化测试可以添加更多场景。
3)编写单元测试有很多好处,而不仅仅是你提到的那个。其他一些好处包括:
5)听起来你做了一个很好的工作,想出可能的测试场景。我认为你得到了所有重要的东西。
答案 4 :(得分:2)
当然,真正的测试数量是无限的。那不切实际。您必须选择有效的代表案例。你似乎已经这样做了。干得好。
答案 5 :(得分:1)
我只想补充一点,通过单元测试,如果您首先考虑可能的情况,并在测试驱动开发方式之后实现,您可以获得更多,因为这将帮助您保持对当前案例和这将使您能够以DRY方式创建最简单的实现。你也可以使用一些测试覆盖工具,例如:在Eclipse EclEmma中,它非常易于使用,并会向您显示测试是否已执行所有代码,这可能有助于您确定何时足够(尽管这不是证据,只是一个指标)。一般来说,在单元测试方面,我受到Kent Becks的测试驱动开发实验书的启发,我强烈推荐它。