![]() |
1
6
为了回答你的一般问题,我会说“一切都要适度”。强调可测试性当然是件大事。但当它以排除可读代码或逻辑API为代价时就不是了。 |
![]() |
2
13
TDD做得好可以提高可读性。TDD做得不好,即不考虑其他重要原则,会降低可读性。 我在90年代中期工作过的一个家伙会说,“你可以通过添加一层间接性使系统更加灵活。你总是可以通过去掉一个间接层来简化一个系统。”灵活性和简单性都是系统的重要品质。这两个原则通常可以和谐地共存,但它们往往是相互对立的。如果你走得太远,走向一个极端或另一个极端,你就会远离理想,这两个原则是平衡的。 TDD部分涉及测试,部分涉及设计。做得不好的TDD会倾向于灵活性或简单性。它可能会带来太多的灵活性。对象变得更容易测试,而且通常更简单,但是域问题的固有复杂性随后被从对象中推出,进入对象的交互。我们获得了灵活性,对于天真的人来说,它看起来像是我们获得了简单,因为我们的对象更简单。然而,复杂性仍然存在。它被移出对象,进入对象交互,在那里它很难控制。这里的代码气味可以充当红色标志——一个系统有数百个小对象,而没有一个大对象,很多只有一行方法的对象是另一个。 做得不好的TDD也可以向另一个方向发展,也就是说,向过于简单的方向发展。所以,我们首先编写测试来完成TDD,但是它对我们的设计影响很小。我们仍然有很长的方法和巨大的对象,这些都是代码的味道,可能会使这个问题变得危险。 现在,只要应用得当,TDD本质上不会让你在任何一个方向失去平衡。用其他的方法来保持你的状态。例如,在做之前先画出你正在做的事情的图片。显然,不是所有的时候。有些事情太简单了。有些图片是值得保存的,有些只是帮助我们形象化问题的草图,而我们在不同程度上主要是视觉学习者。如果你不能画出问题的图片,你就不明白。 这对TDD有何帮助?这将有助于防止系统在灵活性方面走得太远,而不是简单方面。如果你画了一幅画,它很难看,那就是一面红旗。有时这是必要的,但通常当你画出图片时,你的大脑会很快看到可以简化的东西。解决方案变得更加优雅和简化,更易于维护,并且工作起来更加愉快。如果你不能或不愿意为你的系统绘制图片,你就失去了这个机会,让你的软件更坚固、更优雅、更美观、更易于维护。 应用这一点是有经验的,一些编码人员永远不会理解良好的平衡所提供的价值。没有一个指标可以告诉你你在正确的地方。如果有人给了你一个达到和谐点的既定方法,那他就是在骗你。更重要的是,他可能自欺欺人却没有意识到。 所以,我对你的问题的回答是“是”:测试所有的东西,不要忘记其他的好原则。 如果与其他良好实践不平衡,任何好的实践都会使你偏离课程。 |
![]() |
3
6
“我错过什么了吗?” 对。 这件事行得通,不是吗? 更重要的是,你可以证明它是有效的。 与它实际工作并且您可以证明它实际工作的事实相比,为可测试性添加的相对复杂度并不是很有趣。此外,您可以进行更改并证明您没有破坏它。 备选方案(可能或可能不起作用,不可能证明它是否起作用,不破坏它就无法进行更改)将软件的价值降低到零。 编辑 “复杂性”是一个很难理解的概念。对复杂性有客观的衡量标准。更重要的是,复杂性的增加创造了价值。增加的复杂性使您具有可测试性、可配置性、后期绑定、灵活性和适应性。 此外,复杂性的客观度量通常集中在方法内的编码,而不是类和对象之间关系的更大复杂性。复杂性似乎是客观的,但它并没有在软件体系结构的所有层定义。 “可测试性”也很难理解。可能存在测试性的客观度量。然而,大多数情况下,这些都是为了测试覆盖率。测试覆盖率并不是一个非常有意义的指标。生产崩溃的可能性如何随测试覆盖范围而变化?没有。 您可以将复杂性归咎于对可测试性的关注。你可以把复杂性归咎于很多事情。如果仔细观察高度可测试的代码,您会发现它也具有高度的灵活性、可配置性和适应性。 挑出“可测试性”作为“复杂性”的根本原因并没有抓住要点。 关键是有许多相互关联的质量因素。”“有效”是总结最重要内容的一种方法。其他不太重要的,包括适应性、灵活性、可维护性。这些额外的因素通常与可测试性相关,它们也可以被消极地描述为“复杂性”。 |
![]() |
4
4
我看到过通过所有单元测试、通过所有自动化接口测试、通过负载测试、通过几乎所有测试的第一手网站,但是很明显,当被人看到时,这些网站存在问题。 这导致了代码分析,发现了内存泄漏、缓存问题、错误代码和设计缺陷。当遵循多个测试方法并且所有测试都通过时,这是如何发生的?没有一个“单元”有内存泄漏或缓存问题,只有整个系统。 我个人认为这是因为所有的东西都是为了通过测试而编写和设计的,而不是为了在设计上优雅、简单和灵活。测试有很多价值。但仅仅因为代码通过了测试,并不意味着它是好代码。这意味着它是“书智能”代码,而不是“街道智能”代码。 |
![]() |
5
3
在我看来,给定一个足够大或重要的软件,增加一些复杂性以提高可测试性是值得的。另外,在我的经验中,复杂度难以理解的地方是,当抽象层被添加到一段本身就不稳定的代码上时(就像密封的框架类)。当从可测试性作为第一原则的角度编写代码时,我发现代码实际上很容易阅读,而且并不比必要的复杂。 事实上,我很难避免增加复杂性。例如,我还没有转向DI/IOC框架,而是只在测试需要的地方手工注入依赖项。另一方面,我最终采用了一种“增加”复杂性的实践——比如模拟框架——我发现复杂性的数量实际上比我想象的要少,而且好处也比我想象的要多。也许,我最终会发现这对DI/IOC框架也是正确的,但是我可能不会去那里,除非我有一个足够小的项目来进行试验,而不会不合理地通过学习新东西来延迟它。 |
![]() |
6
3
“还是我错过了什么?” 在可测试代码的程度和复杂代码的程度之间存在着隐含的直接关系。如果这是你的经验,我会说 you're doing it wrong . 代码不必更复杂,也可以更容易测试。将代码重构为更具可测试性,确实倾向于使代码更灵活、更小块。这并不一定意味着更复杂(这已经是一个负荷术语),或者需要在一定距离内采取行动。 不知道细节,我只能给出一般性的建议。检查你是否不仅仅是在使用本周的模式。如果您有一个方法需要大量的设置或复杂的方法来覆盖它的行为,那么通常会有一系列更简单的、确定性的方法。提取这些方法,然后您可以更容易地对它们进行单元测试。 测试不必像代码测试那样干净和设计良好。通常情况下,最好在测试中做一些通常是讨厌的黑客行为,而不是对代码进行大量的重新设计。这对于失败测试特别有用。需要模拟数据库连接失败?将connect()方法短暂替换为始终失败的方法。需要知道磁盘满后会发生什么?将文件打开方法替换为失败的方法。有些语言很好地支持这种技术(Ruby、Perl),而其他语言则不太支持。通常可怕的风格变成了一种对生产代码透明的强大的测试技术。
我要明确地说的一件事是,永远不要将只对测试有用的代码投入生产。任何事情
|
![]() |
7
3
可测试产品是一种提供了回答有关它的问题的机会的产品。可测试性和质量一样,是多维的和主观的。当我们将产品评估为(不)可测试性时,重要的是要认识到对某些人的可测试性可能会被添加到其他人身上,或者对其他人来说不必要的复杂性。 对于程序员来说,具有大量单元测试的产品可能是非常好的测试工具,但是如果没有自动化的钩子,那么对于测试工具匠来说,该产品可能很难测试。然而,同样的产品,如果它有一个干净的工作流程、一个优雅的用户界面和日志记录,那么它可以被一个交互式黑盒测试人员完美地测试。没有单元测试的产品可能写得很清楚,很容易被检查和审查,这是另一种测试形式。 我说的是可测试性 here . 詹姆斯·巴赫谈到它 here . --- Michael B. |
![]() |
8
2
(这完全是从程序员的角度写的。对于更面向客户的回答,我建议迈克尔·博尔顿的回答。) 如果您正在编写的应用程序是10行代码,那么是的,添加测试会大大增加复杂性。您可以查看它并手动测试它,您可能会没事的。100行,不多,1000行,不多,10000行,100000行…等。 第二个轴是变化的。这个海湾基地/曾经/改变过吗?多少钱?代码更改得越多,测试就越有价值。 所以,是的,对于一个150行的代码应用程序,它是一个从EDI格式到EDI格式的转换脚本,它以永远不会改变的批处理模式运行,繁重的单元测试可能会被过度终止。 一般来说,对于大型应用程序,我发现将代码更改为可测试的可以提高设计和API的质量。因此,如果您正在编写更大的东西,或者将迭代开发这些东西,并且认为(自动化)单元测试具有高成本/低价值,那么我将认真研究一下为什么您认为这是事实。 一种解释是你的老板对模式上瘾。另一种可能是,您将模式和测试视为是/否全部或无全部讨论。第三个问题是代码已经被编写出来了,而你害怕的是重新编写的代码是可测试的。如果是这样的话,我建议采用外科手术的方法——专注于一些快速增加价值的高强度降压测试。随着代码的发展,缓慢地增长您的测试套件。当您看到价值和简单性(而不是复杂性)时,重构为模式。 |
![]() |
9
1
这种方法的好处会回来, 如果 应用程序将足够大。否则,这只是浪费时间。有时,即使拖放“编码”并遵循SmartUI模式也足够令人满意。 |
![]() |
10
1
从描述上看,这听起来像是项目失去了对杨氏的跟踪,开发了大型结构,以便在需要时进行测试。 在TDD中,一切都是通过测试来证明的,所以事实上您拥有所有这些IOC、DI、AOP要么是使现有测试通过的最简单的解决方案,要么(更可能)是使代码可测试的超引擎解决方案。 我所看到的导致这种复杂性的一个错误是希望测试遵循设计,而不是相反。可能发生的情况是,保持某种难以测试的设计的愿望导致引入各种解决方案来打开API,而不是开发一个更简单、更容易测试的API。 |
![]() |
11
1
无论好坏,TDD都帮助我将应用程序分解为更易于管理的组件,在这些组件中,我独立测试项目的能力迫使我保持简洁。当我向其他人介绍我的代码时,这些测试也是一个很好的文档来源。通过这些测试可以很好地检查应用程序的工作情况,在这种情况下,事物被充分隔离,因此您可以将您的头围绕在功能部件上。另一个不错的副产品是,当您在一个应用程序中使用了一个设计模式时,测试与您使用该模式的其他应用程序具有相似性。 尽管如此,实现命令模式是非常愚蠢的,当你知道应用程序只会执行两个函数时,你只会有两个命令。现在你已经为编写一系列测试而感到苦恼了。得到了什么?您总是可以测试公共方法,但是有了一个适当的模式,您就有了复杂的事情要处理,并且在您必须维护的所有额外的测试中产生了技术债务。 另一个需要考虑的因素是您的团队可以支持什么级别的架构。所有团队成员是否都具有相同的TDD理解水平,或者是否会有少数人能够理解测试?看到一个模拟的物体会让人的眼睛变得呆滞吗?仅仅是这一点就成了不及时完成维护工作的阻碍因素吗? 最后,应用范围也需要驱动设计。为了“纯粹”而复杂不是很好的判断。TDD不会造成这种情况;相反,缺乏经验也会造成这种情况。 |
![]() |
12
0
我不知道您所说的几乎不可读是什么意思,因为即使在使用AOP和DI时,每个部分都应该很容易理解。由于这些技术的存在,理解整个应用程序可能会更加复杂,但这更多的是能够用模型或文本来解释应用程序是如何工作的。 我目前正在开发一个没有单一单元测试的应用程序,因此,现在我开始引入DI来帮助简化测试,但是,这会使其他开发人员更难理解系统,因为可以插入不同的具体类,并且在查看app.config文件之前,您不会知道哪个类是哪个。 这可能导致他们认为代码是不可读的,因为它们不能简单地从一个功能级别流到另一个功能级别,而是必须进行一次侧移,以查看要使用的具体类。 但是,从长远来看,这将是一个更加灵活和稳定的系统,所以我认为有必要进行一些培训。:) 您可能只需要了解如何为应用程序获得更好的系统模型,以了解所有东西是如何联系在一起的。 |
![]() |
13
0
在这种情况下,测试不是问题所在,它的设计模式和整个体系结构都有问题,这通常受到 Joel 和 Jeff 在与建筑宇航员的讨论中。这里,我们有一些基于“哇酷架构”的设计方案,如果1个设计模式是好的,2个必须是好的,3个必须是好的——让我们看看我们可以用多少模式来创建这个应用程序。 如果测试可能是使这些模式可靠工作的必要条件(嗯,这确实说明了一些问题),但是您不应该把测试好与一些体系结构设计差混为一谈。 所以,不,不用担心就可以专注于测试——例如,极限编程是一种非常简单的开发方法,它专注于测试,如果你以这样一种自由形式编写你的应用程序,你可能不会陷入困境,你不是测试驱动开发的错误,而是所做的设计选择。 如果你可以开始废弃它,那么就这么做——可维护性是软件中最重要的因素,如果不容易修改,那么你可以密封它并重新开始,因为维护它可能会花费你更多的钱。 |
![]() |
Vedant · 如何解决python啦啦队长问题?[已关闭] 2 年前 |
![]() |
cobby · 在战略模式中使用工厂模式? 3 年前 |
![]() |
Nobody · Java中带while循环的三角形模式 3 年前 |
![]() |
Eduard Stefanescu · 如何在层之间传输异常? 7 年前 |
![]() |
D. Schreier Talha Noyon · 对于目录中的每个类 7 年前 |
![]() |
Tanvi Jaywant · 如何重载类 7 年前 |