ASP.NET 5 单元测试中使用依赖注入

简介:

在上一篇博文中,主要说的是,使用 TestServer 对 ASP.NET 5 WebApi 进行单元测试,依赖注入在 WebApi Startup.cs 中完成,所以 UnitTest 中只需要使用 TestServer 启动 WebApi 站点就可以了,因为整个解决方案的对象都是用 ASP.NET 5 “自带”的依赖注入进行管理,所以,在对 ASP.NET 5 类库进行单元测试的时候,我都是手动进行 new 创建的对象,比如针对 Application 的单元测试,贴一段 AdImageServiceTest 中的代码:

namespace CNBlogs.Ad.Application.Tests
{
    public class AdTextServiceTest : BaseTest
    {
        private IAdTextService _adTextService;

        public AdTextServiceTest(ITestOutputHelper output)
            : base(output)
        {
            Bootstrapper.Startup.ConfigureMapper();

            IUnitOfWork unitOfWork = new UnitOfWork(dbContext);
            IMemcached memcached = new EnyimMemcached(null);
            _adTextService = new AdTextService(new AdTextRepository(dbContext),
                new AdTextCreativeRepository(dbContext),
                new UserService(memcached),
                unitOfWork,
                memcached);
        }

        [Fact]
        public async Task GetByAdTextsTest()
        {
            var adTexts = await _adTextService.GetAdTexts();
            Assert.NotNull(adTexts);
            adTexts.ForEach(x => Console.WriteLine($"{x.Title}({x.Link})"));
        }
    }
}

AdImageServiceTest 构造函数中的代码,是不是看起来很别扭呢?我当时这样写,也是没有办法的,因为依赖注入的配置是写在 Startup 中,比如下面代码:

namespace CNBlogs.Ad.WebApi
{
    public class Startup
    {
        public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
        {
            // Set up configuration sources.
            var builder = new ConfigurationBuilder()
                .AddJsonFile("appsettings.json")
                .AddEnvironmentVariables();
            Configuration = builder.Build();
        }

        public IConfigurationRoot Configuration { get; set; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddMvc();

            services.AddSingleton<IUnitOfWork, UnitOfWork>();
            services.AddScoped<IDbContext, EFDbContext>();
            services.AddSingleton<IAdTextRepository, AdTextRepository>();
            services.AddSingleton<IAdTextService, AdTextService>();
        }
    }
}

这样设计导致的结果是,针对类库项目的单元测试,就没办法使用依赖注入获取对象了,我后来想使用针对 WebApi 单元测试的方式,来对类库进行单元测试,比如用 TestServer 来启动,但类库中没有办法获取所注入的对象,构成函数注入会报错,[FromServices] 属性注入是 MVC Controller 中的东西,并不支持,所以针对类库的单元测试,和 WebApi 的单元测试并不是一样。

IServiceCollection 的程序包是 Microsoft.Extensions.DependencyInjection.Abstractions,我原来以为它和 ASP.NET 5 Web 应用程序相关,其实它们也没啥关系,你可以脱离 ASP.NET 5 Web 应用程序,独立使用它,比如在类库的单元测试中,但如果这样设计使用,我们首先需要做一个工作,把 Startup.cs 中的 ConfigureServices 配置,独立出来,比如放在 CNBlogs.Ad.Bootstrapper 中,这样 Web 应用程序和单元测试项目,都可以使用它,减少代码的重复,比如我们可以进行下面设计:

namespace CNBlogs.Ad.Bootstrapper
{
    public static class Startup
    {
        public static void Configure(this IServiceCollection services, string connectionString)
        {
            services.AddEntityFramework()
                .AddSqlServer()
                .AddDbContext<EFDbContext>(options => options.UseSqlServer(connectionString));

            services.AddEnyimMemcached();

            ConfigureMapper();

            services.AddSingleton<IUnitOfWork, UnitOfWork>();
            services.AddScoped<IDbContext, EFDbContext>();
            services.AddSingleton<IAdTextRepository, AdTextRepository>();
            services.AddSingleton<IAdTextService, AdTextService>();
        }

        public static void ConfigureMapper()
        {
            Mapper.CreateMap<CNBlogs.Ad.Domain.Entities.AdText, AdTextDTO>();
        }
    }
}

ASP.NET 5 WebApi 项目中的 Startup.cs 配置会非常简单,只需要下面代码:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure(Configuration["data:ConnectionString"]);//add using CNBlogs.Ad.Bootstrapper;
}

好了,做好上面工作后,单元测试中使用依赖注入就非常简单了,为了减少重复代码,我们可以先抽离出一个 BaseTest:

namespace CNBlogs.Ad.BaseTests
{
    public class BaseTest
    {
        protected readonly ITestOutputHelper output;
        protected IServiceProvider provider;

        public BaseTest(ITestOutputHelper output)
        {
            var connectionString = "";
            var services = new ServiceCollection();
            this.output = output;
            services.Configure(connectionString);////add using CNBlogs.Ad.Bootstrapper;
            provider = services.BuildServiceProvider();
        }
    }
}

可以看到,我们并没有使用 TestServer,而是手动创建一个 ServiceCollection,它有点类似于我们之前写依赖注入的 Unity Container,不过它们有很大不同,ServiceCollection 的功能更加强大,从 Bootstrapper.Startup 中可以看到,它可以注入 EF、MVC、Memcache 等等服务对象,BuildServiceProvider 的作用就是获取注入的服务对象,我们下面会用到:

namespace CNBlogs.Ad.Repository.Tests
{
    public class AdTextServiceTest : BaseTest
    {
        private IAdTextService _adTextService;

        public AdTextServiceTest(ITestOutputHelper output)
            : base(output)
        {
            _adTextService = provider.GetService<IAdTextService>();
        }

        [Fact]
        public async Task GetByAdTextsTest()
        {
            var adTexts = await _adTextService.GetAdTexts();
            Assert.NotNull(adTexts);
            adTexts.ForEach(x => Console.WriteLine($"{x.Title}({x.Link})"));
        }
    }
}

这段代码和一开始的那段代码,形成了鲜明对比,这就是代码设计的魅力所在!!!




本文转自田园里的蟋蟀博客园博客,原文链接:http://www.cnblogs.com/xishuai/p/aspnet5-unit-test-dependency-injection.html,如需转载请自行联系原作者

相关文章
|
7月前
|
自然语言处理 测试技术 C#
NSubstitute:一个简单易用、灵活多变的.NET单元测试模拟框架
NSubstitute是一个开源的.NET单元测试模拟类库,该框架设计的主要目标是提供一个简单明了、易用性强、贴近自然语言的模拟测试框架。它使得开发者能够专注于测试工作,而不是纠结于测试替代实例的创建和配置。
78 5
|
1月前
|
JavaScript Java 测试技术
单元测试使用依赖注入
单元测试使用依赖注入
18 2
|
9月前
|
开发框架 前端开发 中间件
ASP.NET Core 中间件的使用(二):依赖注入的使用 (下)
ASP.NET Core 中间件的使用(二):依赖注入的使用 (下)
|
9月前
|
开发框架 中间件 .NET
ASP.NET Core 中间件的使用(二):依赖注入的使用 (上)
ASP.NET Core 中间件的使用(二):依赖注入的使用
|
开发框架 .NET 图形学
几十行代码实现ASP.NET Core自动依赖注入
几十行代码实现ASP.NET Core自动依赖注入
193 0
|
开发框架 .NET 容器
Autofac入门与替代ASP.NET CO re、 ABP依赖注入容器
Autofac入门与替代ASP.NET CO re、 ABP依赖注入容器
608 0
|
自然语言处理 JavaScript 前端开发
JS中的依赖注入 — 在测试中未使用过的最佳工具
让我来为大家介绍在测试中最好的朋友。
JS中的依赖注入 — 在测试中未使用过的最佳工具
|
Java 测试技术 API
.net core实践系列之短信服务-Api的SDK的实现与测试(二)
.net core实践系列之短信服务-Api的SDK的实现与测试(二)
137 0
.net core实践系列之短信服务-Api的SDK的实现与测试(二)
|
XML JSON API
.net core实践系列之短信服务-Api的SDK的实现与测试(一)
.net core实践系列之短信服务-Api的SDK的实现与测试(一)
256 0
.net core实践系列之短信服务-Api的SDK的实现与测试(一)

热门文章

最新文章