用xUnit.net在单元测试中实现构造函数依赖注入

来源:网络 责任编辑:栏目编辑 发表时间:2013-07-02 00:52 点击:

英文关键词:Constructor Dependency Injection and Unit Testing(为了方便英文搜索)

自从博客园开发团队将开发架构迁移至DDD(领域驱动开发),就开始正式使用“构造函数依赖注入”,由CNBlogs.Infrastructure.CrossCutting.IoC(IoC容器抽象层,目前默认容器用的是Unity)负责。

通过构造函数进行依赖注入,避免了在代码中针对所依赖的接口创建相应的实例,这个工作改由IoC容器在运行时自动完成。我们主要在APS.NET MVC的Controller与应用层的服务实现中使用。

比如下面的APS.NET MVC Controller示例代码:

public class AdminController : Controller{    private IBlogSiteManagementService _blogSiteService;    public AdminController(IBlogSiteManagementService blogSiteService)    {        _blogSiteService = blogSiteService;    }}ASP.NET MVC会在运行时通过IoC容器获取IBlogSiteManagementService的实现,并传递给AdminController的构造函数。(这个操作是在DefaultControllerFactory.Create方法中完成的,参见ASP.NET MVC源代码DefaultControllerFactory.cs第259行)

注:要让ASP.NET MVC支持依赖注入,需要实现IDependencyResolver接口,并将所有MVC自带的IController的实现注册到你所用的IoC容器。

自从成功用上了依赖注入,差点成为依赖注入“控”,看到需要依赖的地方,就想着注入。

爱情是不是也可以依赖注入?在你心中声明一下你心仪的女孩的样子,然后丘比特就会给你注入。。。

进入正题。。。

改变博客园团队开发方式的不仅是DDD(领域驱动开发),还有TDD(测试驱动开发)。有了轻微的依赖注入“控”,在写测试代码时,我们不由自主地想到了测试类的构造函数依赖注入。

可是尝试了几个主流的.NET测试框架(MsTest, NUnit, MbUnit, xUnit.net),连带参数的构造函数都不支持,更别谈构造函数依赖注入。

搜遍互联网,也没发现有人试图解决这个问题。

刚开始TDD时,我们就被这个问题困扰,似乎是一个暂时无法解决的问题。。。于是,这就成为了一个可望而不可及的梦想。

不能注入,那只能在无参构造函数中手动获取所依赖接口的实现实例,示例代码(用的是xUnit.net)如下:

public class MyPostList{    private IBlogSiteManagementService _blogSiteService;    public MyPostList()     {        _blogSiteService = IoCFactory.Instance.CurrentContainter            .Resolve<IBlogSiteManagementService>();    }    [Fact]    public void Get_My_Recent_Admin_Posts()    {        Assert.NotNull(_blogSiteService);    }       }昨天开始,我们决定攻克这个难题,比较了几个测试框架,最终选择了xUnit.net(MsTest由于没有开源,根本没考虑)。

选择的理由是xUnit.net是NUnit的开发者开发的,扩展性很好。

解决的思路很简单:找到测试运行时测试类的实例化是在哪进行的。

有了源代码,让这个寻找过程轻松了很多。

xUnit.net在Visual Studio中也是通过TestDriven.net加载的,所以打开xUnit的源代码,直奔主题,进入xunit.runner.tdnet项目,打开TdNetRunner.cs,然后顺藤摸瓜:

Xunit.TestRunner() > Xunit.ExecutorWrapper.RunClass() > Xunit.Sdk.Executor.RunTests() > TestClassCommandRunner.Execute() > TestCommandFactory.Make() > LifetimeCommand.Execute() 在Xunit.Sdk.LifetimeCommand.Execute(object testClass)中发现了瓜:

public override MethodResult Execute(object testClass){    if (testClass == null)        testClass = method.CreateInstance();}method.CreateInstance()实际调用的代码是这样的:

public object CreateInstance(){    return Activator.CreateInstance(method.ReflectedType);}一看代码就知道为什么只支持无参的构造函数。

看到瓜,就容易找到解决方法,既然在 testClass == null 时才会创建测试类的实例,如果我们通过IoC容器在这个方法执行前创建testClass的实例并传递LifetimeCommand.Execute方法,不就可以解决问题了吗?

所以,继续顺藤摸瓜,找出在哪里调用了LifetimeCommand.Execute(object testClass)方法。。。

在Xunit.Sdk.TestClassCommandRunn

    相关新闻>>

      发表评论
      请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
      用户名: 验证码:点击我更换图片
      最新评论 更多>>

      推荐热点

      • 浅析.NET下XML数据访问新机制
      • asp.net 面试+笔试题目第1/2页
      • C# 邮件地址是否合法的验证
      • C#高级编程:数据库连接[1]
      • asp.net 设置GridView的选中行的实现代码
      • 经典C++程序1
      • IIS 自动回收导致后台定时器失效的问题解决
      • ASP.NET&#160;GridView列表代码示例
      • 微软ASP.NET站点部署指南(3):使用Web.Config文件的Transforma
      网站首页 - 友情链接 - 网站地图 - TAG标签 - RSS订阅 - 内容搜索
      Copyright © 2008-2015 计算机技术学习交流网. 版权所有

      豫ICP备11007008号-1