问题
你有没有对你的应用程序进行更改,一切运行得很好但是当你去运行你的单元测试时,所有的地狱失败?这是我的具体问题。可以公平地说,那些不是好的测试,因为当我的应用程序工作正常时它们会失败吗?通过'工作',我的意思是它通过了所有验收测试,每个功能都按预期工作。
背景
在我对我的应用程序进行更改之后的大部分时间我都可以毫无问题地运行所有功能,然后当我运行单元测试时,我将失败。因此,在某些情况下,我花费大量时间更新单元测试,这些测试对于完美的应用程序来说是失败的。我的直觉告诉我,如果你的测试失败,当应用程序通过时,那么它们就是无用的测试,他们正在做的就是提醒开发人员他们刚刚做出的实现更改。这是错的吗?如果相关应用程序中没有其他内容失败,那么良好的测试是否会失败?
示例方案
您有单元测试可以验证是否返回了某个文件名,例如fileName.txt
。代码中的任何地方都使用常量IMPORTANT_FILENAME
引用该文件,因此更改文件名不会影响您的应用程序。您决定将文件名从“fileName.txt”更改为“NewFileName.txt”。您的应用程序可以正常工作,但verify(fileName,'fileName.txt')
上的单元测试失败。这是一个粗略的例子,但我希望你明白这一点。这里的要点是,当我发现自己在工作应用程序上更新单元测试时,在我看来它是一个红旗,这是一个糟糕的测试。我想不出任何在通过的应用程序中失败的测试。但在我使用此作为经验法则并开始删除之前,我想得到一些反馈。你同意吗;单元测试不应该在通过的申请中失败吗?
旁注:我认为这不重要,但我使用Java,Junit和Mockito。
答案 0 :(得分:2)
对我来说,单元测试的主要目的是
因此,如果您更改了对您的应用程序至关重要的内容(即更改功能)并且单元测试没有失败,则表明您的单元测试结果不佳。可能存在例如单元测试以确保所有字段都是equals / hashcode的一部分。或者可能存在单元测试以确保某些类是不可变的。您的功能测试可能仍然有效,但您引入了不需要的代码。
另一个非常重要的事情是可能进行TDD(测试驱动开发)。
答案 1 :(得分:2)
在你的例子中,是的,这是一个糟糕的测试。如果API合同要返回IMPORTANT_FILENAME
的内容,则测试应该测试该内容,而不是硬编码字符串。
通常,如果测试被破坏,则应用程序不一定会失败。单元测试的目的不是确保应用程序功能,而是强制执行api合同。
但即使是这种情况,简单的逻辑规则也会告诉你"应用程序失败=>测试被打破"是不等同于到"测试被破坏=>申请失败"。
答案 2 :(得分:1)
如果您在不更改任何测试的情况下对应用程序进行更改,我肯定希望至少有一个测试失败!验证代码段的测试应该以某种方式中断。其余的测试仍然应该通过,因为他们应该使用模拟。
因此,当某些内容发生变化时,您必须至少对测试进行一些细微的更改。
但是,如果您花费太多时间来修复损坏的测试,则可能会有脆弱的测试。在没有看到问题代码的情况下,很难说要改变什么,但是您应该将尽可能多的软件工程原理和模式应用于您的测试代码作为您的生产代码。尽量不要复制和粘贴代码块。通过继承,辅助方法或类重用代码。这样,如果您需要进行影响许多测试的更改,您只需在一个地方进行更改。
答案 3 :(得分:1)
当您无意中破坏应用程序的某些部分时,单元测试会提醒您。有时候,它们会给你误报。但是偶尔发生误报比将臭虫投入生产更好。
所以,是的,因为你重新设计了你的单位互相交流的方式,所以单位测试有时会失败是可以的。这并不意味着他们的考试不好。当你确实破坏你的应用程序时,最好有这样的测试,而不是不要被警告。
答案 4 :(得分:0)
当应用程序中没有任何内容失败或可能失败时,良好的测试可能会失败。通常,单元测试应涵盖可能发生的应用程序的某些方面。但是,即使您能够编写涵盖每个场景的测试脚本(一个很大的假设),也可能是一个好的单元测试与任何此类场景无关。但是,谁知道某人是否可以改变与此类测试相关的应用程序。假设您实现了Map类,但您的应用程序从不使用remove(Key)方法。但是,您已经实现了删除(密钥)单元测试。即使您的应用程序当前从未使用过remove方法,但有些人可能会在某个时候出现并使用该方法。