您现在的位置是:网站首页> 内容页

XUnit 依赖注入

  • www.710kk.com
  • 2019-05-22
  • 159人已阅读
简介XUnit依赖注入Intro现在的开发中越来越看重依赖注入的思想,微软的Asp.NetCore框架更是天然集成了依赖注入,那么在单元测试中如何使用依赖注入呢?本文主要介绍如何通

XUnit 依赖注入

Intro

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

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

Scoped

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

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

Singleton

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

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

Tips

如果有多个类需要依赖注入,可以通过一个基类来做,这样就只需要一个基类上添加 [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

这里以一个对 Controller 测试的测试为例

    自定义 Fixture

    /// <summary> /// A test fixture which hosts the target project (project we wish to test) in an in-memory server. /// </summary> public class TestStartupFixture : IDisposable { private readonly IWebHost _server; public IServiceProvider Services { get; } public HttpClient Client { get; } public string ServiceBaseUrl { get; } public TestStartupFixture() { var builder = WebHost.CreateDefaultBuilder() .UseUrls($"http://localhost:{GetRandomPort()}") .UseStartup<TestStartup>(); _server = builder.Build(); _server.Start(); var url = _server.ServerFeatures.Get<IServerAddressesFeature>().Addresses.First(); Services = _server.Services; ServiceBaseUrl = $"{url}/api/"; Client = new HttpClient() { BaseAddress = new Uri(ServiceBaseUrl) }; Initialize(); } /// <summary> /// TestDataInitialize /// </summary> private void Initialize() { // ... } public void Dispose() { Client.Dispose(); _server.Dispose(); } private static readonly Random Random = new Random(); private static int GetRandomPort() { var activePorts = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners().Select(_ => _.Port).ToList(); var randomPort = Random.Next(10000, 65535); while (activePorts.Contains(randomPort)) { randomPort = Random.Next(10000, 65535); } return randomPort; } }

    自定义Collection

    [CollectionDefinition("TestCollection")] public class TestCollection : ICollectionFixture<TestStartupFixture> { }

    自定义一个 TestBase

    [Collection("TestCollection")] public class ControllerTestBase { protected readonly HttpClient Client; protected readonly IServiceProvider ServiceProvider; public ControllerTestBase(TestStartupFixture fixture) { Client = fixture.Client; ServiceProvider = fixture.Services; } }

    需要依赖注入的Test类写法

public class AttendancesTest : ControllerTestBase { public AttendancesTest(TestStartupFixture fixture) : base(fixture) { } [Fact] public async Task GetAttendances() { var response = await Client.GetAsync("attendances"); Assert.Equal(HttpStatusCode.OK, response.StatusCode); response = await Client.GetAsync("attendances?type=1"); Assert.Equal(HttpStatusCode.OK, response.StatusCode); } }

Reference

https://xunit.github.io/docs/shared-context.html

Contact

如果您有什么问题,欢迎随时联系我

Contact me: weihanli@outlook.com

文章评论

Top