Xunit项目中的依赖注入

Posted

技术标签:

【中文标题】Xunit项目中的依赖注入【英文标题】:Dependency injection in Xunit project 【发布时间】:2018-06-19 06:12:23 【问题描述】:

我正在开发一个 ASP.Net Core MVC Web 应用程序。

我的解决方案包含 2 个项目:

一个用于应用程序和 第二个项目,专门用于单元测试 (XUnit)。

我在 Tests 项目中添加了对应用程序项目的引用。

我现在要做的是在 XUnit Tests 项目中编写一个类,它将通过实体框架与数据库进行通信。

我在应用程序项目中所做的是通过构造函数依赖注入来访问我的DbContext 类。

但我不能在我的测试项目中这样做,因为我没有 Startup.cs 文件。在这个文件中,我可以声明哪些服务可用。

那么我该怎么做才能在测试类中获得对我的DbContext 实例的引用?

【问题讨论】:

试试 xunit 框架中内置的 xunit di 支持:nuget.org/packages/Xunit.Di,这样您就可以像对任何其他应用程序一样注入服务依赖项。 【参考方案1】:

您可以实现自己的服务提供者来解析DbContext

public class DbFixture

    public DbFixture()
    
        var serviceCollection = new ServiceCollection();
        serviceCollection
            .AddDbContext<SomeContext>(options => options.UseSqlServer("connection string"),
                ServiceLifetime.Transient);

         ServiceProvider = serviceCollection.BuildServiceProvider();
    

    public ServiceProvider ServiceProvider  get; private set; 


public class UnitTest1:IClassFixture<DbFixture>

    private ServiceProvider _serviceProvider;

    public UnitTest1(DbFixture fixture)
    
        _serviceProvider = fixture.ServiceProvider;
    

    [Fact]
    public void Test1()
    
        using (var context = _serviceProvider.GetService<SomeContext>())
        
        
    

但请记住,在单元测试中使用 EF 并不是一个好主意,最好模拟 DbContext。

The Anatomy of Good Unit Testing

【讨论】:

什么是 DatabaseSeeder ?我应该将 DbFixture 放在 Service 子文件夹中吗? 哎呀复制粘贴错误。您可以将DbFixture 放在测试项目中的任何位置。我创建TestSetupTestInfrastructure 文件夹并将这些类放在这些文件夹中。 我使用的是这个,而不是你的 AddEntityFrameworkSqlServer 行:serviceCollection.AddDbContext(options => options.UseSqlServer("connection string") 有很大的不同吗? 没有,两者都可以正常工作,AddEntityFrameworkSqlServer 注册了额外的服务。 @Matt 我修复了断开的链接。【参考方案2】:

您可以使用Xunit.DependencyInjection

【讨论】:

扩展它的作用以及为什么它比其他方法更好在这里会非常有用。另外添加一个小样本来展示它在使用时的外观会很棒。 ***.com/questions/63269460/… 解决问题【参考方案3】:

对于单元测试,您需要模拟您的上下文。

有一个很棒的用于模拟的 nuget 包,称为 Moq。

一些帮助您入门:

public ClassName : IDisposable

    private SomeClassRepository _repository;
    private Mock<DbSet<SomeClass>> _mockSomeClass;

    public ClassName() 
    
        _mockSomeClass = new Mock<DbSet<SomeClass>>();

        var mockContext = new Mock<IApplicationDbContext>();
        mockContext.SetupGet(c => c.SomeClass).Returns(_mockSomeClass.Object);

        _repository = new SomeClassRepository(mockContext.Object);
    

    public void Dispose()
    
        // Anything you need to dispose
    

    [Fact]
    public void SomeClassTest()
    
        var someClass = new SomeClass()  // Initilize object ;

        _mockSomeClass.SetSource(new[]  someClass );

        var result = _repository.GetSomethingFromRepo( ... );

        // Assert the result
    

对于集成测试,你做同样的事情,但设置是:

_context = new ApplicationDbContext();

确保您的 TestClass 继承自 IDisposable (TestClass : IDisposable),以便您可以在每次测试后处理上下文。

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

【讨论】:

xunit 中没有设置,属性。改用构造函数。【参考方案4】:

您可以使用包 Microsoft.EntityFrameworkCore.InMemory

var _dbContextOptions = new DbContextOptionsBuilder&lt;DbContext&gt;().UseInMemoryDatabase(Guid.NewGuid().ToString()).Options;

然后

var context = new DbContext(_dbContextOptions);

【讨论】:

以上是关于Xunit项目中的依赖注入的主要内容,如果未能解决你的问题,请参考以下文章

是否可以将依赖注入与 xUnit 一起使用?

更优雅的在 Xunit 中使用依赖注入

spring中的依赖注入有啥用?

译 Node.js 中的依赖注入

Spring依赖注入

Swift 中的依赖注入