【问题标题】:Dependency injection in Xunit projectXunit项目中的依赖注入
【发布时间】: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,这样您就可以像对任何其他应用程序一样注入服务依赖项。

标签: dependency-injection asp.net-core-mvc xunit


【解决方案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

【讨论】:

  • 扩展它的作用以及为什么它比其他方法更好在这里会非常有用。另外添加一个小样本来展示它在使用时的外观会很棒。
【解决方案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);

【讨论】:

    猜你喜欢
    • 2021-08-05
    • 2020-03-14
    • 1970-01-01
    • 1970-01-01
    • 2020-08-18
    • 1970-01-01
    • 2019-09-03
    • 1970-01-01
    • 2017-01-15
    相关资源
    最近更新 更多