最近为了给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的请求,分析代码覆盖率等,如果我有时间的话,会继续完善这个框架的。

 

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

新项目,WebTest的更多相关文章

  1. swift开发新项目总结

    新项目用swift3.0开发,现在基本一个月,来总结一下遇到的问题及解决方案   1,在确定新项目用swift后,第一个考虑的问题是用纯swift呢?还是用swift跟OC混编      考虑到新项目 ...

  2. 用Kotlin开发Android应用(II):创建新项目

    这是关于Kotlin的第二篇.各位高手发现问题,请继续“拍砖”. 原文标题:Kotlin for Android(II): Create a new project 原文链接:http://anton ...

  3. 在AndroidStudio v1.2.0中导入或增加新项目或工程(导入第三方类库或工程)

    以下说明基于AndroidStdudio版本v1.2 由于AndroidStudio项目止录与Eclipse中的Worksapce在意义上的改变,所以导入新包或建立新项目时并不和以前那样了. 下面是我 ...

  4. 【Cocos2d-x for WP8 学习整理】(1)创建一个新项目

    喜大普奔                         10.1假期之前看到了一个很振奋的消息,就是随着Cocos2d-x 2.2的发布,WP8/WIN8有史以来第一次的合并到主版本了. 之前 V2 ...

  5. cocos2d-x 3.2 创建新项目问题

    cocos2d-x 3.2 执行cocos2d-x\tools\cocos2d-console\console下的cocos2d.py,输入相应的参数即可创建一个新的项目,具体参数网上介绍一大堆,就不 ...

  6. Myeclipse中导入新项目报叹号

    Myeclipse中导入新项目报红色叹号 原因是导入项目中,有的jar路径不对, 在上图中,先把报错的jar移除,之后将JRE开头的那个library移除,最后点击add Library,选择jre. ...

  7. cocos2d-x3.2创建新项目失败的一种可能性(cygwin自带的python2.6被抢先执行)

    之前一直使用cocos2d-x2.2写游戏,写了几个游戏后,想尝试下3.x版本的新功能,就下载了cocos2d-x3.2版本. 参照官方文档的说法,cocos2d-x3.x版本需要python2.7环 ...

  8. fir.im Weekly - 从零开始创建 Android 新项目

    今年的 Google I/O 大会上,人工智能和虚拟现实的产品发布让我们对未来多了几分惊喜.对于开发者部分,Google 发布了 Android N 系统,感受最深的是全新的 Android Stud ...

  9. AndroidStudio创建新项目报错

    创建新项目自动执行时报错: Failed to import new Gradle project: failed to find Build Tools revision 17.0.0 Consul ...

  10. 从零开始的Android新项目1 - 架构搭建篇

    记录一下新项目的搭建. 试想一下,如果没有历史负担,没有KPI压力,去新搭建一个项目,你会怎么设计和实现呢? 本系列文章不是教你怎么从0开始学Android,从0开始怎么建一个项目,而定位于零负担的情 ...

随机推荐

  1. Jq基础简介

    jQuery就是用原生js写出的框架集(Write less do more ) 1.需要注意的问题?(1).jQuery语法需要重新学习(2).jQuery需要注意版本之间的兼容性 (3)不是越新的 ...

  2. ftp文件上传下载实用命令

    连接 >ftp yourhost >user yourusername >password your password 顺利的话连接成功 >dir ;获取remote目录列表 ...

  3. Linux安全基础:配置network

    在 Linux 系统中,TCP/IP 网络是通过若干个文本文件进行配置的,需要编辑这些文件来完成联网工作.系统中重要的有关网络配置文件有以下几项: /etc/sysconfig/network/etc ...

  4. 了解HTML CSS布局(层叠样式表)

    CSS全称为"层叠样式表(Cascading Style Sheets)", 它主要是用于定义HTML内容在浏览器内显示的样式, 比如文字, 颜色, 视觉上的静态效果, 布局等等. ...

  5. Feathers组件的宽度或高度属性,为什么我得到的值是0

    Feathers组件使用一个失效系统延迟一会儿繁重的重绘,这样你可以在一个时间内改变多个属性.如果你还没有明确地设置宽度和高度,他们会自动 调整自身到一套“理想”的尺度.然而,这并不会发生,直到他们验 ...

  6. JavaScript语言精粹(读书笔记)

    第一章 精华 1,JavaScript的函数(主要)基于词法作用域(lexical scoping)的顶级对象.强类型语言允许编译器在编译时检测错误,但弱类型很自由,无需建立复杂的类层次,不用做强制造 ...

  7. django中html过滤器filter

    http://blog.csdn.net/iloveyin/article/details/49560559 safe让Html标签以及一些特殊符号(如<)生效,下面以例子说明: # value ...

  8. Create view failed with ORA-01031:insufficient privileges

    有时候在ORACLE数据库创建视图时会遇到:ORA-01031:insufficient privileges错误,我也多次碰到了各种创建视图出错的情况,很多时候也没有太在意,今天被一同事问起这个问题 ...

  9. asp.net signalR 专题—— 第一篇 你需要好好掌握的实时通讯利器

    一:背景 我们知道传统的http采用的是“拉模型”,也就是每次请求,每次断开这种短请求模式,这种场景下,client是老大,server就像一个小乌龟任人摆布, 很显然,只有一方主动,这事情就没那么完 ...

  10. SQL Server自动化运维系列——监控性能指标脚本(Power Shell)

    需求描述 一般在生产环境中,有时候需要自动的检测指标值状态,如果发生异常,需要提前预警的,比如发邮件告知,本篇就介绍如果通过Power shell实现状态值监控 监控值范围 根据经验,作为DBA一般需 ...