单元测试 (Unit Testing) 是dev testing的核心,它的优点有很多很多,但真正能够享受到其众多优点的项目确不多。我想这主要是因为,在我们开发实践中人们还是对单元测试有一些误解的,其中最大两个误解就是 :
“只要有单元测试就不需要功能测试和集成测试,开发人员可以完全取代测试人员。”
“单元测试不能发现新Bug, 成本太高,看不到回报。”
写单元测试的关键是要搞清楚被测试的 function/API有哪些外部依赖(external dependency),如:数据库、文件、注册表以及其他的API等。
http://research.microsoft.com/en-us/projects/pex/molestutorial.pdf
要点:
- Unit test 针对的是应用程序中最小的可测试单元
- Unit test 的难点在于 - 程序总是和外部有着千丝万缕的联系,如何将可测试的单元孤立出来测试(Test in Isolation)。
- Unit Test vs. Integration Test
- Integration test 不是 self-contained
- 3A pattern - Arrange, Act, Assert
- 两种隔离被测试代码和外部依赖的方法:(1)重构代码,在被测试代码和外部依赖之间引入一个抽象层(interface)。 (2)在运行时绕过外部依赖。
- Dependency injection - Constructor injection
单元测试常用工具
Beginning Mocking With Moq - 1, 2, 3
要想真正理解Moq, 必须要对Lambda Expression 和Expression Tree和Predicate有了解
=== JavaScript 代码单元测试 ===
JavaScript代码的单元测试框架有很多,比较成熟和热门的有QUnit (Cookbook)和Jasmine。这里很长的一组讨论, 关于Looking for a better JavaScript Unit Test Tool。考虑到 jQuery 当下相当普及,其推荐的 QUnit 更具竞争力。QUnit支持同步和异步的测试用例,How to Test your JavaScript Code with QUnit是一篇不错的文章,介绍了QUnit的基本知识,特别是关于asyncTest()的介绍。
但光有JavaScript的单元测试框架还不够,接下来要做的就是如何将这些测试的执行与持续集成(CI,Continuous Integration)系统,如:TFS, 相结合。要达到类似C#代码的持续集成测试的效果。Unit Testing JavaScript as Part of TFS Build 和JavaScript Unittest in Build给出了一些参考方向。
Chutzpah 是一款CodePlex上的开源工具,它支持在Visual Studio中执行JavaScript单元测试 (vsix安装包下载 ),也支持以命令行方式执行单元测试(下载),这一点功能很赞 ,因为有了命令行方式我们就可以很容易将Chutzpah集成到msbuild和CI中。Chutzpah - a JavaScript Test Runner 是一篇非常不错的入门学习文章。
关于命令行方式执行JavaScript单元测试,很多人会有一个很自然的疑问,它是怎样启动浏览器来执行的单元测试用例呢? 答案:Chutzpah依赖于另一个开源项目PhantomJS。简单的讲,PhantomJS是一个Headless Browser, 也就是一个无界面的浏览器。被Chutzpah使用进行惊醒headless testing,其实只是PhantomJS的用途只有,它还可以被用来进行:页面自动化、网络监控和屏幕获取等,参加 Quick Start。PhantomJS貌似非常强大,几乎干了一个标准浏览器的所有工作啊! 其实不然,PhantomJS背后其实也是依赖开源的浏览器引擎 - WebKit。WebKit是三大浏览器引擎之一,另外二位为Gecko和Trident。Apple的Safari和Google的Chrome和Andriod都采用的是Webkit。Firefox是使用的是Gecko,IE则是Trident。
编写单元测试的朋友一定都了解 mock,JavaScript代码的单元测试同样也需要,尤其是针对AJAX请求的mock。Mockjax 就是这样一个专门用来mock AJAX请求的开源库,Mockjax的使用非常简单,可以和前面提到过的Qunit搭配在一起使用。Mock Your Ajax Request with Mockjax for Rapid Development 是一篇介绍Mockjax的好文。
=== Dependency Injection ===
Unity - Developer's Guide to Dependency Injection using Unity ***** 第二章对 Factory Method Pattern -> Simple Factory Pattern-> Abstract Factory Pattern介绍简单易懂,通过比较列出了三种Pattern的各自的特点。
Dependency Injection包括连个环节 : Register 和 Resolve。以Unity为例,Register代码如下:
var container = new UnityContainer();
container.RegisterType<ITenantStore, TenantStore>();
Resolve来获取需要的对象,代码如下所示:
var controller = container.Resolve<ManagementController>();