VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > Python基础教程 >
  • C#教程之XUnit 依赖注入

Intro#

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

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

Scoped#

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

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

Singleton#

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

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

Tips#

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

Samples#

Scoped Sample#

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


Copy
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 测试的测试为例

  1. 自定义 Fixture

    
    
    Copy
    /// <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; } }
  2. 自定义Collection

    
    
    Copy
    [CollectionDefinition("TestCollection")] public class TestCollection : ICollectionFixture<TestStartupFixture> { }
  3. 自定义一个 TestBase

    
    
    Copy
    [Collection("TestCollection")] public class ControllerTestBase { protected readonly HttpClient Client; protected readonly IServiceProvider ServiceProvider; public ControllerTestBase(TestStartupFixture fixture) { Client = fixture.Client; ServiceProvider = fixture.Services; } }
  4. 需要依赖注入的Test类写法


Copy
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

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

相关教程