惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

小众软件
小众软件
A
About on SuperTechFans
博客园 - Franky
Engineering at Meta
Engineering at Meta
Recent Announcements
Recent Announcements
云风的 BLOG
云风的 BLOG
B
Blog
Microsoft Security Blog
Microsoft Security Blog
L
LangChain Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
U
Unit 42
Martin Fowler
Martin Fowler
Y
Y Combinator Blog
Stack Overflow Blog
Stack Overflow Blog
博客园 - 叶小钗
Vercel News
Vercel News
Apple Machine Learning Research
Apple Machine Learning Research
The Cloudflare Blog
Last Week in AI
Last Week in AI
腾讯CDC
Microsoft Azure Blog
Microsoft Azure Blog
爱范儿
爱范儿
V
V2EX
G
Google Developers Blog

博客园 - Ivony...

扩展 DbUtility (1) DbUtility v3 背后的故事 DbUtility v3 Jumony Core 3,真正的HTML引擎,正式版发布 Jumony Core 2.2 发布 尝鲜Jumony for MVC,体验插件化网站开发 用网站(WebSite而不是WebProject)项目构建ASP.NET MVC网站 浅谈ASP.NET网站的编译模型和参数 C#5纯属YY的展望 Jumony for MVC现状和展望 通过源代码研究ASP.NET MVC(八) 通过源代码研究ASP.NET MVC(七) Jumony入门(四)无缝体验 Jumony入门(三)初探解析器 Jumony入门(二)初识选择器 Jumony入门(一)从这里开始 一段自动搜索所有SVN工作目录进行更新的PowerShell脚本 通过源代码研究ASP.NET MVC中的Controller和View(六) 通过源代码研究ASP.NET MVC中的Controller和View(五)
新项目,WebTest
Ivony... · 2013-11-02 · via 博客园 - Ivony...

最近为了给Jumony for ASP.NET进行单元测试有点伤神,ASP.NET因为环境特殊,一直是单元测试的禁地,传统的单元测试工具由于运行在非ASP.NET环境,可谓是举步维艰。当然,微软在搞ASP.NET MVC的时候已经注意到了这一点,雇了很多个临时工把HttpContext以及所有的相关类型全部写了个Base和Wrapper类型,用来Mock一个HttpContext假装在ASP.NET环境。有了这些对象,测试个MVC的Controller和Action也够用了(只是我还没找到自动Mock这一大坨对象的方法)。但是ASP.NET环境显然不止这些,譬如说大家很少用到的VirutalPathUtility就在其列。由于Jumony for ASP.NET是个框架性质的项目,所以一些框架底层不常用的东西随处可见。当然,也有人不堪其扰,对这个东西也改造了一番:

还有这个:

但这些都是internal的,我不能直接用之,再说,指不定哪天就成了public的,我的还与其冲突。最后,我也没有微软那么多临时工去一个个方法Mock出来。想来想去,我的要求再简单不过,只要有个HttpRuntime就好了,不妨直接用真的ASP.NET环境。

用真的ASP.NET环境有几个方案,VS自带的测试工具支持ASP.NET的测试,但是摸索了半天,发现局限大的很,还只能测试aspx文件,用起来也非常的不方便,完全不能满足我的要求,遂放弃。

然后又想,干脆自己用控制台搭一个ASP.NET运行环境出来,这样的话就可以自己发个请求进去,让里面的代码执行个结果扔出来。虽说微软提供了自己搭建ASP.NET环境的类型和工具,但是由于宿主和ASP.NET环境是在两个AppDomain,通信不便不说,调试起来也特别麻烦,网站编译什么都是事儿。

最后,终于想到,TMD干脆自己在ASP.NET环境搭一个单元测试框架算了。话说其实一个单元测试框架就是找到测试方法然后全部跑一次,再看看有没有什么AsertException之类的东西,显示出来就完了。我直接在ASP.NET环境搭一个,整个单元测试都在网站跑,就什么问题都解决了。

然后,就有了WebTest这个开源项目:

https://github.com/Ivony/WebTest

既然是重新搞,那新的技术神马的全都给用上,以前的Assert是个静态类,一大堆的静态方法,有些断言没有就只好转换成真假再去判断。新的框架索性把Assert弄成个对象,所有的断言方法都给整成扩展方法,你们爱有多少断言就有多少,不够再来补充包。以前的测试得自己写个静态类,然后每个方法都要加个[TestMethod]告诉框架这个方法是个测试用的,而我觉得这纯属多余。只需要写一个类型,里面所有的无参public方法全部都被认为是测试方法,反正框架都会一个个来跑。

确定好思路后,做起来还是很快的。首先我想到要有一个类型负责运行测试。

然后来设计这个类型:

  1. 首先我们可以得到一个测试类型,把测试类型丢给TestManager,就可以进行测试(RunTest)。
  2. TestManager得到测试类型后,应当创建一个实例来测试,因为所有的测试方法都是实例方法(RunTest)。
  3. 对实例进行测试(RunTest)时,应当找出哪些方法是用来测试的方法(FindTestMethods)。
  4. 找到测试方法后,要给测试方法创建调用器(CreateInvoker),便于快速调用测试。
  5. 运行完测试方法后,要创建测试结果(TestResult),测试结果有三种,成功(Success)、失败(Failure)、异常(Exception)。
  6. 创建测试结果前,要获取当前测试方法的信息(GetTestInfo),放在测试结果中。

设计后的结果就是如下图:

再加上一个找到所有测试类的静态方法,TestManager就差不多了。

然后是设计TestResult类型,呈现结果的时候,最关键的只有两个元素,消息和是否成功,然后针对三种测试结果,设计三个派生类:

再然后定义一个测试基类,继承于这个类型的所有类型都是测试类:

Initialize和Cleanup现在都可以定义为这个基类的虚方法,如果需要的话就重写好了,事实上查找测试类型的时候,查找基类比查找Attribute要快,我想不通现在的测试框架为啥都要弄个特性来标识。

测试基类提供了一个Assert对象,这个对象可以用来进行断言:

因为所有的断言方法都做成扩展方法,所以断言失败的时候需要调用Failure方法来描述断言失败了。

至此,OOD就基本完成了,然后是一些细节的实现。

查找所有测试类型:

找所有测试方法:

创建Invoker:

事实上,如果熟悉ASP.NET MVC的代码,这些看似高深的东西并不费神。

最后,写一个IHttpHandler作为总控,运行测试,并显示测试结果,然后,就可以直接写单元测试用例了。

当然,作为一个单元测试框架,目前还有诸多欠缺的地方,例如伪造指定URL的请求,分析代码覆盖率等,如果我有时间的话,会继续完善这个框架的。

事实上,单元测试并不难,即使是搭建一个测试框架,也就是几百行代码的事情,我们有什么理由不去做呢?