C#   发布时间:2022-04-03  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了XUnit 依赖注入大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

XUnit 依赖注入

Intro

现在的开发中越来越看重依赖注入的思想,微软的 Asp.Net Core 框架更是天然集成了依赖注入,那么在单元测试中如何使用依赖注入呢?

本文主要介绍如何通过 XUnit 来实现依赖注入, XUnit 主要借助 SharedContext 来共享一部分资源包括这些资源的创建以及释放。

Scoped

针对 Scoped 的对象可以借助 XUnit 中的 IClassFixture 来实现

@H_489_12@
  • 定义自己的 Fixture,需要初始化的资源在构造方法里初始化,如果需要在测试结束的时候释放资源需要实现 IDisposable 接口
  • 需要依赖注入的测试类实现接口 IClassFixture<Fixture>
  • 在构造方法中注入实现的 Fixture 对象,并在构造方法中使用 Fixture 对象中暴露的公共成员
  • Singleton

    针对 Singleton 的对象可以借助 XUnit 中的 ICollectionFixture 来实现

    @H_489_12@
  • 定义自己的 Fixture,需要初始化的资源在构造方法里初始化,如果需要在测试结束的时候释放资源需要实现 IDisposable 接口
  • 创建 CollectionDeFinition,实现接口 ICollectionFixture<Fixture>,并@L_874_8@一个 [CollectionDeFinition("CollectionName")] Attribute,CollectionName 需要在整个测试中唯一,不能出现重复的 CollectionName
  • 在需要注入的测试类中@L_874_8@ [Collection("CollectionName")] Attribute,然后在构造方法中注入对应的 Fixture
  • Tips

    • 如果有多个类需要依赖注入,可以通过一个基类来做,这样就只需要一个基类上@L_874_8@ [Collection("CollectionName")] Attribute,其他类只需要集成这个基类就可以了

    Samples

    Scoped Sample

    这里直接以 XUnit 的示例为例:

    public class DatabaseFixture : IDisposable
    {
        public DatabaseFixture()
        {
            Db = new sqlConnection("MyConnectionString");
    
            // ... initialize data in the test database ...
        }
    
        public void Dispose()
        {
            // ... clean up test data from the database ...
        }
    
        public sqlConnection Db { get; private set; }
    }
    
    public class MyDatabaseTests : IClassFixture<DatabaseFixture>
    {
        DatabaseFixture fixture;
    
        public MyDatabaseTests(DatabaseFixture fixturE)
        {
            this.fixture = fixture;
        }
    
    
        [Fact]
        public async Task Gettest()
        {
            // ... write tests,using fixture.Db to get access to the sql Server ...
            // ... 在这里使用注入 的 DatabaseFixture
        }
    }
    

    Singleton Sample

    这里以一个对 asp.net core API 的测试为例

    @H_489_12@
  • 自定义 Fixture
  • /// <sumMary>
    /// Shared Context https://xunit.github.io/docs/shared-context.html
    /// </sumMary>
    public class APITestFixture : IDisposable
    {
        private readonly IWebHost _server;
        public IserviceProvider services { get; }
    
        public httpClient Client { get; }
    
        public APITestFixture()
        {
            var baseUrl = $"http://localhost:{GetRandomPort()}";
            _server = WebHost.CreateDefaultBuilder()
                .UseUrls(baseUrl)
                .UseStartup<TestStartup>()
                .build();
            _server.Start();
    
            services = _server.services;
    
            Client = new httpClient(new WeihanLi.Common.http.NoProxyhttpClientHandler())
            {
                BaseAddress = new Uri($"{BaseUrl}")
            };
            // Add Api-Version Header
            // Client.DefaultrequestHeaders.TryAddWithoutValidation("Api-Version","1.2");
    
            Initialize();
    
            Console.WriteLine("test begin");
        }
    
        /// <sumMary>
        /// TestDataInitialize
        /// </sumMary>
        private void Initialize()
        {
        }
    
        public void Dispose()
        {
            using (var dbContext = services.Getrequiredservice<ReservationDbContext>())
            {
                if (dbContext.Database.IsInMemory())
                {
                    dbContext.Database.Ensuredeleted();
                }
            }
    
            Client.Dispose();
            _server.Dispose();
    
            Console.WriteLine("test end");
        }
    
        private static int GetRandomPort()
        {
            var random = new Random();
            var randomPort = random.Next(10000,65535);
    
            while (IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners().Any(p => p.port == randomPort))
            {
                randomPort = random.Next(10000,65535);
            }
    
            return randomPort;
        }
    }
    
    [CollectionDeFinition("APITESTCollection")]
    public class APITESTCollection : ICollectionFixture<APITestFixture>
    {
    }
    
    1. 自定义Collection
    [CollectionDeFinition("TESTCollection")]
    public class TESTCollection : ICollectionFixture<TestStartupFixture>
    {
    }
    
    1. 自定义一个 TESTBase
    [Collection("APITESTCollection")]
    public class ControllerTESTBase
    {
        protected httpClient Client { get; }
    
        protected IserviceProvider services { get; }
    
        public ControllerTESTBase(APITestFixture fixturE)
        {
            Client = fixture.Client;
            services = fixture.services;
        }
    }
    
    1. 需要依赖注入的Test类写法
    public class NoticeControllerTest : ControllerTESTBase
    {
        public NoticeControllerTest(APITestFixture fixturE) : base(fixturE)
        {
        }
    
        [Fact]
        public async Task GetNoticeList()
        {
            using (var response = await Client.GetAsync("/api/notice"))
            {
                Assert.Equal(httpStatusCode.oK,response.StatusCodE);
                var responseString = await response.Content.ReadAsStringAsync();
                var result = JsonConvert.DeserializeObject<PagedListModel<Notice>>(responseString);
                Assert.NotNull(result);
            }
        }
    
        [Fact]
        public async Task GetNoticeDetails()
        {
            var path = "test-notice";
            using (var response = await Client.GetAsync($"/api/notice/{path}"))
            {
                Assert.Equal(httpStatusCode.oK,response.StatusCodE);
                var responseString = await response.Content.ReadAsStringAsync();
                var result = JsonConvert.DeserializeObject<Notice>(responseString);
                Assert.NotNull(result);
                Assert.Equal(path,result.NoticeCustomPath);
            }
        }
    
        [Fact]
        public async Task GetNoticeDetails_NotFound()
        {
            using (var response = await Client.GetAsync("/api/notice/test-notice1212"))
            {
                Assert.Equal(httpStatusCode.NotFound,response.StatusCodE);
            }
        }
    }
    

    运行测试,查看我们的 APITestFixture 是不是只实例化了一次,查看输出日志:

    XUnit 依赖注入

    可以看到我们输出的日志只有一次,说明在整个测试过程中确实只实例化了一次,只会启动一个 web server,确实是单例的

    @H_920_119@memo

    微软推荐的是用 @H_363_14@microsoft.AspNetCore.Mvc.TesTing 组件去测试 Controller,但是个人感觉不如自己直接去写web 服务去测试,如果没必要引入自己不熟悉的组件最好还是不要去引入新的东西,否则可能就真的是踩坑不止了。

    Reference

    大佬总结

    以上是大佬教程为你收集整理的XUnit 依赖注入全部内容,希望文章能够帮你解决XUnit 依赖注入所遇到的程序开发问题。

    如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

    本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
    如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
    标签: