这个问题可能看起来有点奇怪,但我会解释它。
考虑以下事项:
我们有一个服务FirstNameValidator
,我为其他开发人员创建了这个服务,因此他们有一致的方法来验证一个人的名字。我想测试它,但因为全套可能的输入是无限的(或非常大),我只测试几个案例:
Assert.IsTrue(FirstNameValidator.Validate("John"))
Assert.IsFalse(FirstNameValidator.Validate("$$123"))
我也有LastNameValidator
,它有99%的相同,我也为它写了一个测试:
Assert.IsTrue(LastNameValidator.Validate("Doe"))
Assert.IsFalse(LastNameValidator.Validate("__%%"))
但后来出现了一个新的结构 - PersonName,它由名字和姓氏组成。我们也想验证它,所以我创建了一个PersonNameValidator。显然,为了可重用性,我只需要调用FirstNameValidator和LastNameValidator。一切都很好,直到我想为它写一个测试。
我应该测试什么?
FirstNameValidator.Validate实际上是用正确的参数调用的吗?
或者我需要创建一些案例并对其进行测试?
这实际上是个问题 - 我们应该测试预期会提供哪些服务?我们希望验证PersonName,它是如何做到的,我们实际上并不关心。因此,我们传递几个有效和无效的输入,并期望相应的返回值。
或者,也许,它实际上做了什么?就像它实际上只是调用其他验证器一样,所以测试(.net模拟框架允许它)。
答案 0 :(得分:1)
单元测试应该是正常运行的代码单元的验收标准...... 他们应该测试代码应该而不应该做什么,在撰写测试时,你经常会发现极端情况。
如果你重构代码,你经常需要重构测试......这应该被视为原始努力的一部分,并且应该让你的灵魂高兴,因为你已经使产品和过程得到了如此大的改进。
当然,如果这是一个具有外部(或内部,取决于公司文化)消费者的图书馆,您需要在完成之前考虑文档。
编辑:这些测试也相当薄弱,你应该对每个测试中的合法内容进行定义,并且实际测试包含和排除至少所有类别的glyphps ...他们仍然可以使用相关代码进行测试...即isValidUsername(name,allowsSpace)
可以同时使用名字和全名,具体取决于是否允许使用空格。
答案 1 :(得分:0)
您提出的问题有点奇怪:您描述的两个选项都将测试函数的行为,但每种情况下的粒度级别不同。在一种情况下,您将根据功能用户可用的API测试行为。该功能是否以及如何借助其他功能/组件来实现其功能无关紧要。在第二种情况下,您将单独测试行为,包括功能与其依赖组件的交互方式。
一般来说,不可能说哪个更好-根据情况,每个选项可能都是最好的。通常,隔离一个软件通常需要更多的精力来实施测试,并使测试对于实现更改更加脆弱。这意味着,仅在有充分理由的情况下才应进行隔离。在讨论您的特定情况之前,我将介绍一些建议隔离的情况。
这些标准可以帮助您做出关于是否需要隔离的明智决定。考虑您的特定示例:您描述情况的方式给我的印象是上述标准均未满足。对于我来说,这将得出一个结论,即我不会将函数PersonNameValidator
与它的DOC FirstNameValidator
和LastNameValidator
隔离开来。