迭代5 建立单元测试
本次迭代
在上一次对Contact Manager的迭代中,我们通过使用一些设计模式对 程序进行了重构,松散了类之间的耦合。我们将controller、service和repository层分别 独立出来。每层都基于接口与其他层进行交互。
通过重构,应用程序变得更以维护 和修改。假如某天你需要使用其他的数据存储技术,那么只要简单的替换repository层即可 ,并不需要去碰controller或service层中的代码。
但当我们需要向Contact Manager中添加新功能或修正bug时呢?残酷的事实告诉我们,每当我们改动代码的时候,也 必定要承担新bug出现的风险。
例如某天,你的头需要你向Contact Manager中添加 一项新功能。她要求程序支持对联系人信息进行分组,她要求用户可以自定义一些如 “朋友”,“同事”租入此类的分组从而组织他们的联系人信息。
为了实现这项功能,你需要修改Contact Manager中全部三层之中的代码。你需要向 controller、service、repository层中添加一系列的新函数。从你开始修改代码的那一刻 开始,你就必须承担有可能破坏原本正常工作的那部分功能的风险。
上次我们将应 用程序重构并将其分散到若干独立的层中,这使得我们可以在不触碰其他代码的情况下对某 层做出改变。然而,当你希望这个具体的层中的代码更易维护和修改时,你应当为代码建立 单元测试。
你可以通过单元测试针对特定的代码单元进行测试。这些代码单元要比 整个层小得多。例如你测试代码中的某个特定的方法,确认其是否达到预期的功能及表现, 这就是一个经典的单元测试场景。如你想要对ContactManagerService类公开的 CreateContact()方法进行单元测试。
单元测试对于整个应用程序的开发过程而言更 像一个安全网络。当你想修改应用程序中的代码时,你可以进行一系列的单元测试来检测是 否你的新代码对原有功能产生了破坏。单元测试为你的代码修改工作提供了更高的安全系数 ,同时单元测试也使得应用程序中的代码变更场景更具弹性。
在这次迭代中,我们 向Contact Manager添加单元测试。得益于此,在下一次迭代中我们可以为其添加新的联系 人分组功能,同时又无需顾虑这些改变是否会对原有功能产生影响。
那么就从这里 开始
在完美的世界中,应用程序中的所有代码都是经过单元测试的。在完美的世界 中,你拥有一个完美的安全网络体系,你可以修改应用程序总的任意一行代码并且立即通过 单元测试得知这些改动是否会对原有的功能产生影响。
然而这个世界在大部分的情 况下还不够完美。在实践中,当我们进行单元测试时,你需要集中精力针对业务逻辑进行测验 (例如,验证逻辑)。在特殊情况下,你无需对数据访问逻辑或视图逻辑进行单元测试。
单元测试必须是可以快速执行的。你将很轻易的为应用程序积累成百上千的单元测 试。如过运行某些单元测试十分耗时,则你应当避免执行它们。换句话说,耗时的单元测试 对日常的编码工作并无益处。
因此,你无需对与数据库实际交互的代码进行单元测 试。运行几百个针对数据库的单元测试将十分缓慢。你应当对你的数据库进行mock,然后编 写代码与mock的数据库进行交互。(下面我们将讨论如何对数据库进行mock)
相似 的,你无需针对view进行单元测试。要想对view进行测试,你就不得不搭建web服务器。因 为搭建web服务器相对来说也很耗时,这里并不推荐针对view进行单元测试。
如果你 的view包含大量复杂的逻辑,则你应当考虑将这些逻辑转移到Helper方法中。你可以针对 Helper方法编写单元测试且无需搭建web服务器。
虽然针对数据存储逻辑或试图的测 试并不被推荐,但这些测试可能在集成测试或功能测试时十分有用。
ASP.NET MVC默 认使用Web Form试图引擎。该引擎依赖于web服务器,其他的试图引擎或许不尽如此。