Questions tagged «unit-testing»

单元测试是一种测试源代码的各个单元以确定它们是否适合使用的方法。

11
严格出于测试目的修改代码是否是错误的做法
我与一名程序员同事讨论关于仅修改一段可工作的代码以使其可测试(例如通过单元测试)是好是坏的做法。 我的观点是,在保持良好的面向对象和软件工程实践的范围内(当然不要“公开一切”等),这是可以的。 我同事的观点是,仅出于测试目的修改代码(有效)是错误的。 只是一个简单的示例,请考虑某些组件(用C#编写)使用的这段代码: public void DoSomethingOnAllTypes() { var types = Assembly.GetExecutingAssembly().GetTypes(); foreach (var currentType in types) { // do something with this type (e.g: read it's attributes, process, etc). } } 我建议可以修改此代码以调出另一个可以完成实际工作的方法: public void DoSomething(Assembly asm) { // not relying on Assembly.GetExecutingAssembly() anymore... } 此方法接受一个Assembly对象进行处理,从而可以通过您自己的Assembly进行测试。我的同事认为这不是一个好习惯。 什么被认为是良好且常见的做法?

10
没有时间进行完整重构时,为遗留代码编写测试是否有意义?
我通常会尝试遵循《与Legacy Cod e 一起有效工作》一书的建议。我打破了依赖关系,将部分代码移到@VisibleForTesting public static方法和新类上,以使代码(或至少部分代码)可测试。并且我编写测试以确保在修改或添加新功能时我不会破坏任何东西。 一位同事说我不应该这样做。他的推理: 最初,原始代码可能无法正常工作。并且为它编写测试使将来的修复和修改变得更加困难,因为开发人员也必须理解和修改测试。 如果它是具有某些逻辑的GUI代码(例如〜12行,例如2-3 if / else块),则由于代码太琐碎而无法开始,因此测试不值得这样做。 类似的不良模式也可能存在于代码库的其他部分中(我还没有看到,我还很新)。一次大的重构就更容易清理它们了。提取逻辑可能会破坏这种未来的可能性。 如果我们没有时间进行完整的重构,是否应该避免提取可测试的部分并编写测试?我应该考虑这样做的不利之处吗?

7
编写现有代码的测试
假设其中一个程序比较大(例如,在C#中为900k SLOC),所有程序都已进行了注释/记录,内容井井有条,运作良好。整个代码库由一个不再在公司工作的高级开发人员编写。所有代码都可以按原样进行测试,并且在整个过程中都使用IoC -出于某些奇怪的原因,他们没有编写任何单元测试。现在,您的公司希望分支代码,并希望添加单元测试以检测更改何时破坏了核心功能。 添加测试是一个好主意吗? 如果是这样,一个人怎么会开始这样的事情? 编辑 好的,所以我没想到答案会得出相反的结论。无论如何,这个问题可能不在我的掌控之中。我也阅读了“重复的问题”,并且普遍的共识是“编写测试很好” ...是的,但是在这种特殊情况下不太有用。 在考虑为遗留系统编写测试时,我并不孤单。我将保留有关花费多少时间以及新测试发现问题的次数(以及没有发现问题的次数)的指标。我会回来,并从现在开始大约一年后用我的结果进行更新。 结论 因此,事实证明,基本上不可能将任何形式的正统测试都添加到现有代码中。代码正常工作后,您显然无法对测试进行红灯/绿灯测试,通常通常不清楚哪些行为对测试很重要,也不清楚不清楚从何处开始,当然也不清楚何时完成。真的,甚至问这个问题都错过了编写测试的重点。在大多数情况下,我发现使用TDD重写代码实际上比解密预期的功能和追溯添加单元测试要容易得多。解决问题或添加新功能时,情况有所不同,我认为现在是添加单元测试的时候了(如下所述)。最终,大多数代码都会被重写,通常比您预期的要早-我采用这种方法


7
使用验收和集成测试代替单元测试是否足够?
这个问题的简短介绍。我现在已经使用TDD,最近使用BDD已经超过一年了。我使用诸如嘲笑之类的技术来更有效地编写测试。最近,我开始了一个个人项目,为自己编写一个小小的资金管理程序。由于我没有遗留代码,因此从TDD开始是一个完美的项目。不幸的是,我没有体验到TDD的喜悦。它甚至破坏了我的乐趣,以至于我放弃了这个项目。 怎么了 好吧,我使用了类似TDD的方法来使测试/需求发展程序的设计。问题在于,超过一半的开发时间用于编写/重构测试。所以最后我不想实现任何其他功能,因为我需要重构并编写许多测试。 在工作中,我有很多遗留代码。在这里,我写了越来越多的集成和验收测试,以及更少的单元测试。这似乎不是一个坏方法,因为大多数错误是通过验收和集成测试检测到的。 我的想法是,最终我可以编写比单元测试更多的集成和验收测试。就像我说的那样,对于检测错误,单元测试并不比集成/验收测试好。单元测试也对设计有益。由于我曾经写过很多文章,所以我的类总是被设计为可测试的。此外,在大多数情况下,让测试/需求指导设计的方法可导致更好的设计。单元测试的最后一个优点是它们更快。我已经写了足够多的集成测试,知道它们可以和单元测试一样快。 在浏览网络后,我发现这里和那里提到的想法非常相似。您如何看待这个想法? 编辑 在一个例子中回答这个设计很好的例子,但是我需要对下一个需求进行大量重构: 首先,执行某些命令有一些要求。我编写了一个可扩展的命令解析器-从某种命令提示符下解析命令,并在模型上调用正确的命令。结果以视图模型类表示: 这里没有错。所有类都彼此独立,我可以轻松添加新命令,显示新数据。 下一个要求是,每个命令应具有其自己的视图表示形式-命令结果的某种预览。我重新设计了程序,以针对新要求实现更好的设计: 这也很好,因为现在每个命令都有自己的视图模型,因此也有自己的预览。 事实是,命令解析器已更改为使用基于令牌的命令解析,并且剥夺了其执行命令的能力。每个命令都有自己的视图模型,数据视图模型只知道当前的命令视图模型,而不知道必须显示的数据。 我现在想知道的是,新设计是否没有违反任何现有要求。我不必更改任何我的验收测试。我不得不重构或删除几乎每个单元测试,这是一大堆工作。 我想在这里展示的是在开发过程中经常发生的一种常见情况。旧的或新的设计都没有问题,它们只是随需求而自然变化-我的理解是,TDD的优点之一就是设计不断发展。 结论 感谢您的所有答案和讨论。在此讨论的总结中,我想到了一种方法,将在下一个项目中对其进行测试。 首先,我在像往常一样执行任何操作之前编写所有测试。 对于需求,我首先编写一些验收测试,以测试整个程序。然后,我为需要实现需求的组件编写了一些集成测试。如果有一个组件与另一个组件紧密协作以实现此要求,那么我还将编写一些集成测试,其中两个组件都需要一起测试。最后但并非最不重要的一点是,如果我必须编写一个具有高排列的算法或任何其他类(例如,序列化程序),我将为此特定类编写单元测试。所有其他类均未经测试,但未经任何单元测试。 对于错误,可以简化过程。通常,错误是由一个或两个组件引起的。在这种情况下,我将为测试该错误的组件编写一个集成测试。如果它与算法有关,我只会编写一个单元测试。如果不容易检测到发生错误的组件,我将编写验收测试以查找错误-这应该是一个例外。

9
如何编写“好的”单元测试?
受此线程的触发,我(再次)正在考虑最终在项目中使用单元测试。那里的一些海报说“如果测试是好的,那么测试很酷”。我现在的问题是:什么是“好”测试? 在我的应用程序中,主要部分通常是某种数值分析,具体取决于大量观察到的数据,并得出可用于对这些数据进行建模的拟合函数。我发现很难为这些方法构建测试,因为可能的输入和结果的数量太大,无法仅对每种情况进行测试,而且这些方法本身通常很长,在不牺牲性能的情况下不易重构。我对这种方法的“良好”测试特别感兴趣。

10
我们应该测试所有方法吗?
所以今天我和队友讨论了单元测试。当他问我“嘿,那堂课的考试在哪儿,我只看到一个?”时,整个事情开始了。整个类都是一个管理器(或服务,如果您喜欢这样称呼它),几乎所有方法都只是将东西委托给DAO,所以它类似于: SomeClass getSomething(parameters) { return myDao.findSomethingBySomething(parameters); } 一种没有逻辑的样板(或者至少我不认为像逻辑这样的简单委托),但是在大多数情况下(层分离等)很有用。我们进行了相当长时间的讨论,是否应该对它进行单元测试(我认为值得一提的是,我对DAO进行了完全单元测试)。他的主要论据是(显然)它不是TDD,并且有人可能希望查看测试以检查此方法的作用(我不知道它怎么可能更明显),或者将来有人可能希望更改该方法。实现并向其中添加新的(或更多类似“ any”的)逻辑(在这种情况下,我猜有人应该只测试该逻辑)。 不过,这让我思考。我们应该争取最高的测试覆盖率吗?还是仅仅是出于艺术的缘故?我根本看不出在进行以下测试之后有任何原因: getter和setter(除非他们实际上有一些逻辑) “样板”代码 显然,对这种方法(带有模拟)的测试将花费我不到一分钟的时间,但我想这仍然是浪费时间,并且每个CI都需要花费一毫秒以上的时间。 是否有任何合理/不“易燃”的理由来说明为什么要测试每一行(或尽可能多的行)代码?

7
代码覆盖突出显示了未使用的方法-我该怎么办?
我的任务是增加现有Java项目的代码覆盖率。 我注意到,代码覆盖率工具(EclEmma)强调了一些从未在任何地方调用的方法。 我最初的反应不是为这些方法编写单元测试,而是向我的生产线经理/团队强调它们,并询问为什么要从那里开始使用这些功能。 最好的方法是什么?为他们编写单元测试,或者质疑为什么要在那里?

11
如果数字没有任何含义,魔术数字在单元测试中可以接受吗?
在单元测试中,我经常在代码中抛出任意值以查看其作用。例如,如果我知道foo(1, 2, 3)应该返回17,则可以这样写: assertEqual(foo(1, 2, 3), 17) 这些数字纯粹是任意的,没有更广泛的含义(例如,它们不是边界条件,尽管我也对此进行了测试)。我很难为这些数字想出好名字,而写类似的东西const int TWO = 2;显然是无济于事的。这样编写测试是否可以,还是应该将数字分解为常量? 在中,所有魔幻数字是否都相同?,我们了解到,如果从上下文可以明显看出含义,则魔术数字是可以的,但是在这种情况下,数字实际上根本没有任何意义。

5
是否有对所有公开进行存根和模拟的单元测试的意义?
当以“适当”的方式进行单元测试时,即对每个公用电话进行存根并返回预设值或模拟,我觉得我实际上并没有进行任何测试。我从字面上看我的代码,并基于通过公共方法的逻辑流创建示例。每次实现更改时,我都必须再次更改那些测试,而不是真的感觉自己正在完成任何有用的事情(无论是中期还是长期的)。我也进行集成测试(包括不愉快的路径),我并不介意增加测试时间。有了这些,我觉得我实际上是在测试回归,因为它们已经捕获了多个,而单元测试所做的只是告诉我,我已经知道,公共方法的实现已更改。 单元测试是一个广泛的话题,我觉得我是一个不了解这里内容的人。与集成测试(不包括时间开销)相比,单元测试的决定性优势是什么?

9
重构前如何编写单元测试?
我已经阅读了类似问题的一些答案,例如“重构时如何保持单元测试正常工作?”。就我而言,情况略有不同,因为我得到了一个项目进行审查并符合我们已有的一些标准,目前该项目根本没有测试! 我已经确定了许多我认为可以做得更好的事情,例如不要在服务层中混合DAO类型的代码。 在重构之前,为现有代码编写测试似乎是一个好主意。在我看来,问题是当我进行重构时,这些测试将随着我改变执行某些逻辑的位置而中断,并且这些测试将牢记先前的结构(模拟的依赖关系等)编写。 就我而言,最好的前进方法是什么?我很想围绕重构的代码编写测试,但是我知道我可能会错误地重构事物,从而可能改变期望的行为。 无论是重构还是重新设计,我都很高兴能理解要更正的术语,目前我正在为重构进行以下定义:“按照定义,重构不会改变软件的功能,您将更改其操作方式。”。因此,我不会更改软件的功能,而是会更改软件的方式/位置。 同样,我可以看到这样一种论点,即如果我更改了可以视为重新设计的方法的签名。 这是一个简单的例子 MyDocumentService.java (当前) public class MyDocumentService { ... public List<Document> findAllDocuments() { DataResultSet rs = documentDAO.findAllDocuments(); List<Document> documents = new ArrayList<>(); for(DataObject do: rs.getRows()) { //get row data create new document add it to //documents list } return documents; } } MyDocumentService.java (无论如何都经过重构/重新设计) public …


5
促进可测试代码的设计原则是什么?(设计可测试代码与通过测试驱动设计)
我从事的大多数项目都将开发和单元测试隔离考虑,这使得以后编写单元测试成为噩梦。我的目标是在高级和低级设计阶段本身都牢记测试。 我想知道是否存在定义明确的设计原则来促进可测试的代码。我最近了解的一个这样的原理是通过依赖注入和控制反转的依赖反转。 我读过有一种叫做SOLID的东西。我想了解是否遵循SOLID原则间接导致了易于测试的代码?如果没有,是否存在任何明确的设计原则来促进可测试的代码? 我知道有些东西称为“测试驱动开发”。虽然,我对在设计阶段本身就考虑到测试的代码设计更感兴趣,而不是通过测试来推动设计。我希望这是有道理的。 与该主题相关的另一个问题是,为了能够为每个模块编写单元测试用例,是否可以重构现有产品/项目并更改代码和设计?

16
为什么在进行TDD时不一次编写所有测试?
TDD的红色-绿色-重构周期已经建立并被接受。我们编写一个失败的单元测试,并使其尽可能简单地通过。与为一个类编写许多失败的单元测试并使它们全部一次性通过相比,这种方法有什么好处。 测试套件仍可保护您避免在重构阶段编写错误的代码或犯错误,那么这有什么危害呢?有时,首先以“大脑转储”的形式首先编写一个类(或模块)的所有测试会更容易,以便一次编写所有预期的行为。

4
TDD-由内而外由内而外
使用TDD 构建应用程序Inside In与使用Inside Out构建应用程序有什么区别? 这些是我阅读的有关TDD和单元测试的书: 测试驱动开发:示例 测试驱动开发:实用指南:实用指南在Microsoft中开发 高质量PHP框架和应用程序的实际解决方案 。 NET xUnit测试模式:重构测试代码 单元测试的技巧:以.Net为例 ,以测试为指导的不断增长的面向对象软件中的示例 --->因为JAVA不是我的主要语言,所以这真的很难理解:) 通常,几乎所有的人都解释了TDD的基础知识和单元测试,但是很少提及构建应用程序的不同方式。 我注意到的另一件事是,这些书中的大多数(如果不是全部)在编写应用程序时都会忽略设计阶段。他们更多地专注于快速编写测试用例并让设计自行出现。 但是,我遇到了xUnit测试模式中的一段,该段讨论了人们处理TDD的方式。有2所学校在外面,在内部与内部。 遗憾的是,这本书没有对此进行详细说明。我想知道这两个案例的主要区别是什么。 什么时候应该使用它们中的每一个? 对于TDD初学者来说,哪个更容易掌握? 每种方法的缺点是什么? 有没有专门讨论该主题的材料?

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.