在大型项目中的某些时间点,为了提取出能加快功能交付的理念,设计往往需要做大型的重构。在我们上一个项目中,我们发掘出了如下理念:
  AutoMapper
  将表单作为单独的命令消息处理
  Input builders
  有了以上这些,单元测试是重构时的保障。但只有我们依赖这些测试来捕获应用程序中所有有趣的行为时,才能有保障的作用。为了允许有效的大中型重构,我们需要增加额外的测试层级。
  皮下测试策略
  皮下测试,顾名思义,所有的测试都是在用户界面之下进行的。在MVC应用程序中,皮下测试是测试控制器下面的所有内容。对于Web service,一切测试都在终端下进行。皮下测试的思想是,应用程序的上层不执行任何实际的业务逻辑,而只是外部接口与底层服务之间的连接。
  皮下测试的重要性体现在我们希望在抛开如用户接口和外部服务这类外部连接点的情况下,能够在整个系统运行的同时测试业务逻辑。相对于单元测试关注小模块的设计,皮下测试关注的不涉及设计,而是测试整个系统的基本输入和输出。
  要建立有效的皮下测试,我们可以尝试通过常见的逻辑流程建立uniform pinch points。例如,我们可以建立一个命令消息处理系统,或一个普通的查询界面。在近的一个处理批处理文件项目上,批处理文件中的每一行都被转换为一条消息。然后,我们创造一条消息,发送给这个系统,然后验证处理该消息的所有异常情况。
  由于皮下测试不是基于设计而是基于高级(业务)行为,它们是理想的基于场景的测试策略,如BDD或Testcase Class per Fixture模式。如果我们要进行大的重构,我们需要这些高层次的测试,为商业行为建立全面的安全保障。由于皮下测试更关注于端对端的逻辑,所以它也是标志功能点完成的一个重要的目标点。
  虽然皮下测试使我们能够安全地执行较大的重构,但它仍无法保证我们可以放心地将系统升级到生产环境。
  全系统测试策略
  起初,我们把全系统测试称为“UI 测试”,直到我们的项目越来越多地牵涉到集成策略。这时输入到我们系统中的不再是浏览器,取而代之的是消息,来自 REST 端点、FTP 或批处理文件。UI 测试只是全系统测试的一个子集。全系统测试背后的思想是,我们想按照软件在生产环境中的使用方式来测试它们。对于一个 MVC 应用程序来说,是基于浏览器的测试。对于批处理文件来说,我们会使用实际的文件。对于 REST 使用实际的 HTTP 请求。对于消息则使用实际的队列和消息。
  如果我们想知道,应用程序在部署到生产环境之前是否能按照预期工作,一个有效而且高效的方法是,创建一个自动化测试来测试整个系统。如果我可以让 UI 测试登录到应用程序中、创建一个订单,然后我可以验证是否产生了一个订单请求,那么我会感觉很良好。
  关于全系统测试的一个常见误区是认为它是黑盒测试。然而,全系统测试的特点在于,你必须对系统内部发生的事情了如指掌。实际上,全系统测试甚至还可以利用域模型来生成数据,而不是一个纯粹为测试目的而构建的系统后门。很多团队容易掉进去的一个大坑是,不按照与生产环境一样的代码路径来测试,这将导致系统处于古怪的、无效的、很难处理的状态。
  在我们的项目中,全系统测试代码是我们在声称一个功能/故事做完之前的所写的后代码。对于描述一个功能的“已完成”特性来说,手工测试的成本太高、而且不可靠。但是,如果我能像在生产环境一样去测试,通过完全一样的外部界面来完成,那这样的手工测试也算是成功的。
  全盘考虑
  在一个未经测试过的应用程序中,作为提高覆盖率的手段,我们发现实际上有价值的测试策略是从全系统测试开始,然后往下移,直至单元测试。我们先做宽松、简单的断言,然后慢慢往下移,直至单元级别的逻辑。在全新开发的应用程序中,我们倾向于不只是特别关注某一个区域,因为对于一个需要长期维护的系统来说,所有的测试都很重要。
  这种测试策略确实需要一定的投资。我们发现,当我们知道这个应用程序对客户的业务有决定性作用的时候,这样的全盘考虑在特别有效。如果一个应用程序对业务有决定性作用,那它将不得不面临变更。当变更来临的时候,我们好能安全地实施变更而不影响客户的业务。
  作者简介
  Jimmy Bogard是德克萨斯州Headspring公司的技术架构师,致力于研究DDD,分部式系统和其他acronym-centric design/架构/方法论的研究.同时也是AutoMapper的创始人和ASP.NET MVC in Action的作者
  原文来自于LosTechies.com.LosTechies是一个公开的论坛,致力于通过一种公开且集中的途径分享技术见解和思维。并且希望所有人能够在思维讨论和借鉴中获得成感和喜悦.