软件测试有效等价类练习题
最近,DHH 发起了有关TDD的激烈辩论,当时他声称TDD已死 。
这场持续不断的辩论成功吸引了包括我们在内的开发人员世界的关注。
在我们的办公室里发生了一些关于进行测试的正确做法的小型辩论。
在本文中,我将发表自己的看法。
您看到了多少种测试?
从我加入行业开始,我就从事以下测试:
- 单元测试
- 系统/集成/功能测试
- 回归测试
- 测试线束/负载测试
- 烟雾测试/蜘蛛测试
以上测试类别不一定是互斥的。 例如,您可以创建一组自动化功能测试或冒烟测试以用作回归测试。 为了让新手受益,让我们快速回顾一下这些旧概念。
单元测试
单元测试旨在测试代码/组件单元的功能。 对于Java世界,代码单元是类,每个Java类都应该具有单元测试。 单元测试的原理很简单。 当所有组件都正常工作时,整个系统应该正常工作。
组件很少单独工作。 而是,它通常与其他组件交互。 因此,为了编写单元测试,开发人员需要模拟其他组件。 这是DHH和James O Coplien批评Unit Test的问题,付出了巨大的努力却收效甚微。
系统/集成/功能测试
没有具体的命名,因为人们经常使用不同的术语来描述相似的事物。 与单元测试相反,对于功能测试,开发人员旨在测试整个系统功能,其中可能涉及多个组件。
通常,对于功能测试,将检索数据并将其存储到测试数据库。 当然,应该在运行之前预先设置好测试数据。 DHH喜欢这种测试。 它可以帮助开发人员测试系统的所有功能,而无需花费大量精力来设置模拟对象。
功能测试可能涉及声明Web输出。 过去,大多数情况是使用htmlUnit完成的,但是随着Selenium Grid的最新改进,Selenium成为了首选。
回归测试
在这个行业中,与开发新系统相比,您可能最终会花费更多的时间维护系统。 软件一直在变化,并且每当进行更改时都很难避免风险。 回归测试应该捕获由更改引起的任何缺陷。
过去,一家软件公司确实有一支测试人员大军,但是当前的趋势是自动化测试。 这意味着开发人员将交付带有全套测试的软件,这些测试应该在功能受损时被破坏。
每当检测到错误时,都应添加新的测试用例以覆盖新的错误。 开发人员创建测试,让测试失败,然后修复错误以使其通过。 这种做法称为测试驱动开发。
测试线束/负载测试
普通测试用例无法捕获系统性能。 因此,我们需要为此目的开发另一组测试。 以最简单的形式,我们可以为在连续集成服务器中运行的功能测试设置超时时间。 这种测试中最棘手的部分是它非常依赖于系统,如果系统过载,则可能会失败。
最受欢迎的解决方案是使用JMeter之类的配置工具来手动运行负载测试,或者创建我们自己的负载测试应用程序。
烟雾测试/蜘蛛测试
烟雾测试和蜘蛛测试是两种与我们更相关的特殊测试。 WDS为无线行业提供KAAS( 知识即服务 )。 因此,我们的应用程序每天都会通过数据更改而不是业务逻辑更改进行刷新。 对我们而言,系统故障可能来自数据更改,而不是业务逻辑。
冒烟测试是在集成服务器上运行带有生产数据的一组预定义测试用例。 它可以帮助我们找出日常LIVE部署的任何潜在问题。
与Smoke Test相似,Spider Test会使用真实数据运行,但其工作原理类似于爬虫,它会随机单击任何可用的链接或按钮。 我们的系统之一包含如此多的输入组合,以至于无法进行人工测试(接近100.000的输入组合)。
我们的冒烟测试会随机选择一些数据组合进行测试。 如果它成功运行了几个小时而没有任何缺陷,我们将继续进行每日/每周部署。
我们环境中的测试文化
简而言之,WDS是TDD的殿堂。 如果在编写测试用例之前创建实现,则最好保持安静。 如果您看一下WDS自我介绍,则只有在敏捷和XP之后才提及TDD。“ 我们是:-敏捷和XP,TDD和配对,Java和JavaScript,git和连续部署,Linux和AWS,牛仔裤和T恤,Tea和蛋糕 ”
WDS中的许多高级主管开始了他们作为开发人员的职业生涯。 作为一家注重工程的公司,这有助于培养我们的文化。 在这里,请求资源以提高测试覆盖率或基础架构很常见。
我们没有质量检查。 在最坏的情况下,产品负责人或客户会发现错误。 最好的情况是,我们在同行评审阶段按测试用例或团队伙伴检测错误。
关于我们的新加坡办事处,我们大多数团队成员都是从小吸收Ken Beck和Martin Fowler的著作和理念成长的。 这就是为什么他们中大多数人都是顽固的TDD崇拜者。 甚至,我们团队的一名成员是马丁·福勒(Martin Fowler)的邻居。
在我们的工作环境中进行测试的重点确实取得了成果。 WDS的生产缺陷率相对较低。
我对测试的经验和个人见解
自我评估就足够了。 现在,让我分享我的测试经验。
通常,自动化测试比质量检查更好
将拥有QA团队的传统软件仓库与提供全面测试覆盖范围产品的现代化敏捷团队的输出进行比较,后者通常在质量上甚至优于性价比。 质量检查工作是否应该很快消失?
监控过度可能暗示质量不足
听起来很奇怪,但是多年来,每当我看到一个包含太多监控层的项目时,我都会感到不安全。 过度监视可能暗示缺乏信心,实际上,这些系统经常因未知原因而崩溃。
编写测试用例花费更多的时间来开发功能
DDH绝对是正确的。 编写测试用例意味着您需要模拟输入并断言很多事情。 除非您继续编写意大利面条式代码,否则与编写测试相比,开发功能所需的时间要少得多。
使用javascript进行UI测试很痛苦
您知道的时候就知道了。 如果只需要测试Restful API或静态html页面,则生活会好得多。 不幸的是,现代Web应用程序开发的趋势在客户端涉及很多javascript。 对于UI测试,异步是邪恶的。
无论您是要使用htmlUnit之类的完全控制测试框架,还是要使用更实用,更通用的Selenium之类的框架,如果您从未遇到随机失败,这都将令我感到惊讶。
我猜每个开发人员都知道由于随机故障测试案例而导致在本周结束时无法通过构建的感觉。
开发人员总是高估他们的软件质量
这对我也适用,因为我是一个乐观的人。 我们倾向于认为,在测试失败或有人帮助指出错误之前,我们的实现是完美的。
有时,我们更改代码以简化测试用例的编写
想要与否,在这一点上我们必须同意DHH。 与Java世界有关,我看到人们公开内部变量,为框架对象(例如HttpSession,HttpRequest等)创建虚拟包装器,以便编写单元测试更加容易。 DHH感到非常不舒服,以至于他选择从Unit Test步行。
在这一方面,我一半同意他,一半不同意他。 我个人认为,为了测试而更改设计和实现是不利的。 如果开发人员可以编写代码而不考虑模拟输入,则更好。
但是,为了获得简单方便的生命而放弃单元测试太极端了。 正确的解决方案应该以一种不会使业务逻辑与框架或基础架构紧密耦合的方式设计系统。
这就是所谓的域驱动设计 。
域驱动设计
对于新手,域驱动设计为我们提供了具有以下几层的系统。
如果您注意到,上面的图表比Rails或Java对Rails, Play框架的采用更多的抽象层。 我知道创建更多的抽象层会导致系统过大,但是对于DDD来说,这是一个合理的折衷方案。
让我们进一步详细说明每一层的内容:
基础设施
在此层中,您可以存储存储库实现或任何其他特定于环境的问题。 对于基础架构,请保持API尽可能简单,虚拟,并避免在此处实现任何业务逻辑。
对于这一层,单元测试是一个笑话。 如果有什么要写的内容,则应该进行集成测试,该测试适用于实际数据库。
域
域层是最重要的层。 它包含所有系统业务逻辑,而无任何框架,基础架构和环境问题。 您的实现应看起来像是用户需求的直接翻译。 任何输入,输出,参数仅是POJO 。
域层应该是要实施的第一层。 为了完全完成逻辑,您可能需要基础结构层的接口/ API。 最佳做法是将API保留在域层中,将具体实现保留在基础结构层中。
域层最好的测试用例是单元测试,因为您所关心的不是系统用户界面或环境。 因此,它有助于开发人员避免对模拟框架对象进行肮脏的工作。
为了模拟对象的内部状态,我的首选是使用Reflection实用程序设置对象,而不是通过setter公开内部变量。
应用层/用户界面
应用层是您开始考虑如何向客户表示业务逻辑的地方。 如果逻辑很复杂或涉及许多连续的请求,则可以创建Facades 。
达到这一点,开发人员应该更多地考虑客户端而不是系统。 主要的问题应该是客户的设备,UI响应性,负载平衡,无状态或有状态会话,Restful API。 这是开发人员展示框架人才和知识的地方。
对于这一层,更好的测试用例是功能/集成测试。
与上述类似,请尽量避免在应用程序层中包含任何业务逻辑。
为什么在Rails中编写单元测试很难?
现在,如果您回头看Rails或Play框架,上面的各层之间并没有明确的分隔。 控制器呈现输入,输出,并且还可以包含业务逻辑。 如果使用ServletAPI而不添加任何其他层,则会应用类似的行为。
Rails中的Domain对象是一个活动记录,并且与数据库模式紧密耦合。
因此,对于开发人员要编写测试用例的任何代码单元,输入和输出都不是POJO。 这使编写单元测试变得困难。
我们不应该将这种设计归咎于DHH,因为他遵循另一种软件开发哲学,具有许多优点,例如简单的设计,较少的开发工作量和快速的反馈。 但是,我本人并没有遵循并采纳他的所有想法来开发企业应用程序。
他的一些想法(如约定优于配置)很棒,确实在开发人员世界中引起了重大的思维方式变化,但其他想法最终却以权衡取舍。 能够快速启动网站可能会在以后导致实现Rails / Play不支持的功能的麻烦。
结论
- 如果您的业务逻辑与框架紧密耦合,则很难编写单元测试。
- 首先关注和开发业务逻辑可以帮助您创建更好的设计。
- 每种组件都适合不同类型的测试用例。
这是我对测试的看法。 如果您还有其他意见,请提供一些意见。
翻译自: https://www.javacodegeeks.com/2014/05/testing-effectively.html
软件测试有效等价类练习题