zoukankan      html  css  js  c++  java
  • [翻译]在ASP.NET MVC中使用TDD与依赖注入

    (代码截图为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)。

  • 相关阅读:
    内网渗透之文件下载
    从跨域与同源策略谈CSRF防御与绕过
    内网渗透之权限维持
    一次关于shiro反序列化漏洞的思考
    冰蝎&哥斯拉 流量特征分析
    第三方提权之数据库提权
    APP渗透测试之安卓APP抓包
    从零开始的信息搜集(二)
    从零开始的信息搜集(一)
    python 进程
  • 原文地址:https://www.cnblogs.com/darkdawn/p/1283692.html
Copyright © 2011-2022 走看看