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

推荐订阅源

Help Net Security
Help Net Security
G
Google Developers Blog
雷峰网
雷峰网
WordPress大学
WordPress大学
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Engineering at Meta
Engineering at Meta
Security Latest
Security Latest
T
Threat Research - Cisco Blogs
AWS News Blog
AWS News Blog
F
Full Disclosure
C
Cybersecurity and Infrastructure Security Agency CISA
T
The Exploit Database - CXSecurity.com
J
Java Code Geeks
U
Unit 42
C
Cyber Attacks, Cyber Crime and Cyber Security
V
V2EX
C
Cisco Blogs
博客园 - 司徒正美
Project Zero
Project Zero
L
LINUX DO - 热门话题
阮一峰的网络日志
阮一峰的网络日志
Blog — PlanetScale
Blog — PlanetScale
Scott Helme
Scott Helme
A
About on SuperTechFans
Hugging Face - Blog
Hugging Face - Blog
S
Securelist
小众软件
小众软件
aimingoo的专栏
aimingoo的专栏
S
Schneier on Security
G
GRAHAM CLULEY
酷 壳 – CoolShell
酷 壳 – CoolShell
Cyberwarzone
Cyberwarzone
MongoDB | Blog
MongoDB | Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 叶小钗
T
Threatpost
Recorded Future
Recorded Future
C
CXSECURITY Database RSS Feed - CXSecurity.com
宝玉的分享
宝玉的分享
N
News and Events Feed by Topic
人人都是产品经理
人人都是产品经理
The Register - Security
The Register - Security
S
Security Archives - TechRepublic
博客园 - Franky
N
News | PayPal Newsroom
Simon Willison's Weblog
Simon Willison's Weblog
S
SegmentFault 最新的问题
W
WeLiveSecurity
A
Arctic Wolf
B
Blog

博客园 - a-peng

My post test IE inline edit how to make hidden element actually hide EntityFramework4.1 Mapping Asp.Net Mvc 3.0 Windbg IOC与AOP Custom Date and Time Format Strings group by Year(CreatedDate), Month(CreatedDate) 用sql, entity sql (linq表达式好像挺复杂) asp.net life cycle OH MY GOD! 我的后台页面都被IE可缓存了。。。 编译器错误消息: 类型“System.Data.Objects.DataClasses.EntityObject”在未被引用的程序集中定义。 让IFrame自适应高度 让IE8使用IE7兼容模式运行 - a-peng - 博客园 Visual Studio 2008 Html Designer无法加载 修改SQLServer2008数据表无法提交 jQuery plugin LazyForm定制您的CheckBox Radio和Select Asp.Net Mvc使用Ajax.BeginForm上传文件Request.Files始终为empty Asp.Net Mvc Ajax偏方 太疯狂了:Teleport Pro......It's incredible.
[转载] [翻译]在ASP.NET MVC中使用TDD与依赖注入
a-peng · 2009-06-18 · via 博客园 - a-peng

此文为转载:http://www.cnblogs.com/darkdawn/archive/2008/09/04/1283692.html 非常好的文章。

(代码截图为ASP.NET MVC

Preview 5版本

原文地址:http://haacked.com/archive/2007/12/07/tdd-and-dependency-injection-with-asp.net-mvc.aspx

在设计ASP.NET MVC Framework的时候,指导原则之一是要能使用TDD(测试驱动开发)建立web应用程序。本文使用ASP.NET MVC CodePlex Preview 4为例(经过测试,代码可以在Preview 5中运行,翻译版截图全部为Preview 5),我将试着保持这篇文章的内容适用于最新的ASP.NET MVC Framework,但是需要多一点点的时间。

本文提供一个稍具测试驱动开发(TDD)风格的web程序,同时介绍把StructureMap DI依赖注入)框架集成到这个ASP.NET MVC示例中。在本文结尾处你可以下载代码。

我选择了StructureMap 2.0依赖注入框架,因为我对它比较熟悉,并且它只需要做很少的代码和配置。如果你想把这个示例换成使用Spring.NET,可以到Fredrik Normen’s post查看。以后我可能会写点使用Castle WindsorObjectBuilder的代码示例。

Start Me Up(向滚石乐队致歉)

首先安装好VS2008以及ASP.NET MVC,打开Visual Studio 2008并选择File|New Project,在对话窗口中选择ASP.NET MVC Application模板。

然后选择单元测试项目选择对话框。

默认安装下,只有Visual Studio Unit Test项目选项可用。但是安装了MbUnitxUnit等等其他框架也会在这里显示出来。

你可能会猜想,我会从建立一个很权威的blog例子,其实我会从没有数据库的示例开始,我们可以以后慢慢添加。

第一件我想做的事是添加一些类文件到主项目中去。我不会添加任何实现,能编译就行。我首先添加这些:

Controllers目录下BlogController.cs

Models目录下IPostRespository.cs

Models目录下Post.cs

MvcApplicationTest项目下BlogControllerTests

完成后,我的项目文件树像这样:

现在我想写足够多的代码让我们可以写一个测试。首先,我定义了容器接口。

对真正的博客帖子容器来说这点内容是不够的,但是这里只是做一个demo而已。当你准备好写一个很强悍的blog引擎的时候,你可以添加更多的方法。

现在我仍然不管Post类,让它继续空着,可以以后再来实现。先实现blogController

好了,在这里打住。我们已经能够开始写单元测试了。毕竟我准备演示TDD嘛。让我们先来写个测试。

Let’s Get Test Started, In Here.(向黑眼豆豆致歉)

从最简单的测试开始,确定Recent这个行为(Action)没有指定视图(View),因为我看到默认行为的运行结果。(这段代码假设你已经引用了所有需要的名称空间)

运行这个测试,会失败。

但这正是我们所期望的,因为我们并没有实现Recent方法。这是TDD红绿重构韵律之红色部分。

还是让我们来把这个方法实现了吧:

注意:我们是把精力集中在行为上,而不是在UI上。这和使用ASP.NET WebForms是不同的。这两者没有孰优孰劣,只是风格不同而已。

现在当我运行测试,会通过。

很好,现在是TDD生命周期的绿色部分了!也只个非常非常简单的TDD例子。现在该我们进入介绍依赖注入阶段了。

It’s Refactor Time(向读者致歉,扯得太远了)

为了获得最近的博客帖子,我想为我的博客Controller提供一个“服务”实例,它可以请求这些帖子。

这时,我不能确定我怎么去存储博客帖子,用什么好呢?SQL?XML?还是其他?

都不是。暂时不要去想它吧。

我们可以把这个讨论延迟到最后的时刻。现在我要创建一个抽象容器IPostRepository,用来描述我想怎么存储和取回这些博客帖子。我们来为blogController写些代码,让它可以在它的构造器中接受一个这个接口的实例。

这是依赖注入的依赖(Dependency)部分。这个Controller现在有一个对IPostResitory的依赖。注入(Injection)部分是一种机制:传递依赖给所需要依赖的类,直接创建类的实例,并绑定类到所指定的接口的实现。

现在修改BlogController类。

很好。注意我并没有改变Recent方法。我需要先写另一个测试,要确保它传递正确的数据给view

注意:你现在会发现刚才我们写的测试不能通过,先注释掉,我们一会再修正它。

我们现在要使用mock框架,在我写测试之前,我需要引用Moq.dll到我的测试项目中,在这里下载MoQ

注意:在本示例项目中已经引用了这个程序集。

这个测试动态创建IPostRepository接口的实现。我们告诉它:不管是什么参数传递给了ListRecentPosts,返回两篇帖子。

注意:我们现在不需要这个接口的实现。我们感兴趣的是把测试Action的逻辑孤立出来,所以在测试的时候我们直接使用了接口实例化。

开始测试,失败了,看来我们需要重构Recent方法,让它正确运行:

重新测试一次,成功了!

Inject That Dependency

当我使用浏览器尝试访问这个action的时候(如http://localhost:14963/Blog/Recent),会出现如下的错误页面:

出现这样的错误很正常,默认情况下,ASP.NET MVC需要Controller有一个public的、无参的构造器,让它自己可以创建Controller的实例。但是我们的构造器需要一个IPostRepository实例作为参数。我们需要给Controller传递一个这样的参数才行。

StructureMap(或其他依赖注入框架)来救援!

注意:记得下载和引用StructureMap.dll程序集。我在示例代码中已经引用了。

首先要在应用程序根目录下创建StructureMap.config文件,文件内容:

这里不对这个文件内容做详细解释,如果你想了解更多,请查看StructureMap文档。

它只暴露了你所需要知道的最少细节,每个PluginFamily节点描述一个接口类型和一个节点的键(key)。Plugin节点描述一个具体的类型:框架实例化接口类型需要创建的具体类型。

比如说,第二个PluginFamily节点中,接口类型是IPostRepository,具体的类型是InMemoryPostRepository。当我们使用StructureMap构造一个包含对IPostRepository依赖的类型的实例时,StructureMap会传递一个InMemoryPostReposity实例。

平时我使用SqlPostRepository。但是这个demo的目的并不需要那么做,所以我打算用个静态集合,把存储这些博客帖子到内存中。我们总是可以不急着实现使用SQL版本。

注意:本来应该写一个InMemoryPostRepository的测试,但是这篇文章已经够长了。不过也别担心,我会把单元测试放到示例代码中去。

快,我们需要一个工厂!

快完成了。我们需要实现IControllerFactory接口,把StructureMap连接到ASP.NET MVC上。Controller工厂的职责是创建Controller的实例。我们可以在自己的工厂中用这些逻辑:

最后,我们吧他们都连接起来,在Global.asax.cs中的Application_Start方法添加方法调用:

一切搞定!现在我们把依赖注入框架引入到了我们的程序中,我们可以重新访问站点测试一下了(别忘记编译)。我们得到这个页面:

很好很强大!黄屏去死吧,不过在这里是个好现象:我们的依赖对象已经注入到对象中了,这是另一个错误提示,因为我们没有view创建view造成的。

不好意思,跑题了。

这里我就不做了,你们可以自己做一个,或者你们可以在傻瓜示例源代码中看到。

这个示例有点简单得可笑,不过这种原则在做更大的项目中也是通用的。它只是用来学习技术的,希望在你在TDD路上走得更好。

本文所有内容的源代码下载(ASP.NET MVC Preview 5/StructureMap 2.0)。