使用 Autofac 的 XUnit 测试构造函数依赖注入

问题描述 投票:0回答:3

我正在用 Autofac 实现 Xunit,我可以通过下面的代码让它工作:

using (var scoped = DbFixture.Container.Resolve<UserReponsitory>())
{
    var result = (scoped.GetAll()).ToList().Count();
    Assert.Equal(2, result);
}

但是我想将 UserReponsitory 注入到测试方法中,而不是使用

DbFixture.Container.Resolve
。是否可以使以下代码工作?
UnitTest1.cs

namespace XUnitTestPro
{
    public class UnitTest1:IClassFixture<DbFixture>
    {
        private IUserReponsitory _userReponsitory;
        public UnitTest1(IUserReponsitory userReponsitory)
        {
            _userReponsitory = userReponsitory;
        }
        [Fact]
        public void Test1()
        {
            //using (var scoped = DbFixture.Container.Resolve<UserReponsitory>())
            //{
            //    var result = (scoped.GetAll()).ToList().Count();
            //    Assert.Equal(2, result);
            //}
            var result = _userReponsitory.GetAll().ToList().Count();
            Assert.Equal(2, result);
        }
    }
}

DbFixture.cs

namespace XUnitTestPro
{
    public class DbFixture
    {
        public static IContainer Container { get; set; }

        public DbFixture()
        {
            var builder = new ContainerBuilder();
            var option = new DbContextOptionsBuilder<UserContext>().UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Database=EFProject;Trusted_Connection=True;MultipleActiveResultSets=true").Options;
            UserContext context = new UserContext(option);
            builder.RegisterInstance(context).As<UserContext>();

            builder.RegisterType<UserReponsitory>().AsSelf().As<IUserReponsitory>();

            builder.RegisterAssemblyTypes(typeof(DbFixture).GetTypeInfo().Assembly);

            Container = builder.Build();

        }
    }
}

目前,我得到了以下错误,这似乎与

IClassFixture<DbFixture>
public UnitTest1(IUserReponsitory userReponsitory)
不同有关。

消息:以下构造函数参数没有匹配 灯具数据:IUserReponsitory userReponsitory

有什么方法可以在不调用的情况下实现以下代码

DbFixture.Container.Resolve
类似于注入 MVC 控制器?

public UnitTest1(IUserReponsitory userReponsitory)
{
    _userReponsitory = userReponsitory;
}

换句话说,我怎么能依赖注入单元测试类?
任何帮助将不胜感激。

asp.net-core autofac xunit2
3个回答
2
投票

xUnit 中的依赖注入支持有点有限。

当你实现

IClassFixture<DbFixture>
接口时,xUnit在它的构造函数中期望一个
DbFixture
参数
,参数的类型取决于
T
中的
IClassFixture<T>

话虽这么说,当您实施

IClassFixture<DbFixture>
时,您的构造函数必须看起来像
public UnitTest1(DbFixture)
。但是你有
IUserRepository
,所以xUnit不知道在那里注入什么。

您还可以实现多个

IClassFixture<T>
类型,但是每个
T
只能在每个测试类中使用一次。

来自关于共享上下文的官方xUnit文档

IClassFixture<T>
):

重要说明:xUnit.net 使用接口 IClassFixture<> 的存在来知道您想要创建和清理类夹具。无论您是否将类的实例作为构造函数参数,它都会这样做。同样,如果你添加了构造函数参数但忘记添加接口,xUnit.net 会让你知道它不知道如何满足构造函数参数。

更新

仍然可以使用 IoC 容器解决它,只是不能使用构造函数注入。

public class DbFixture
{
    public IContainer Container { get; private set; }

    public DbFixture()
    {
        var builder = new ContainerBuilder();
        var option = new DbContextOptionsBuilder<UserContext>().UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Database=EFProject;Trusted_Connection=True;MultipleActiveResultSets=true").Options;
        UserContext context = new UserContext(option);
        builder.RegisterInstance(context).As<UserContext>();

        builder.RegisterType<UserReponsitory>().AsSelf().As<IUserReponsitory>();

        builder.RegisterAssemblyTypes(typeof(DbFixture).GetTypeInfo().Assembly);

        Container = builder.Build();
    }
}

public class UnitTest1:IClassFixture<DbFixture>
{
    private IUserReponsitory _userReponsitory;
    public UnitTest1(DbFixture fixture)
    {
        // resolve it here
        _userReponsitory = fixture.Container.Resolve<IUserRepository>();
    }

    [Fact]
    public void Test1()
    {
        //using (var scoped = DbFixture.Container.Resolve<UserReponsitory>())
        //{
        //    var result = (scoped.GetAll()).ToList().Count();
        //    Assert.Equal(2, result);
        //}
        var result = _userReponsitory.GetAll().ToList().Count();
        Assert.Equal(2, result);
    }
}

但是,问题是这样的方法好用吗?不确定你想要达到什么,但如果你想做unit测试,那么你不必在所有或具体类中使用 IoC 容器,只需模拟和你正在测试的类型。

如果您想在 ASP.NET Core MVC / WebApi 上进行集成测试,那么您应该使用

TestServer
类,该类使用您已经在那里配置的所有 IoC 启动整个应用程序。


0
投票

如果您已经在单元测试中启用了构造函数注入,那么您就快完成了。在测试的构造函数中,注入 a

Func<Owned<UserReponsitory>>

例如

namespace XUnitTestPro
{
public class UnitTest1:IClassFixture<DbFixture>
{
    private Func<Owned<UserReponsitory>> _userRepositoryFactory;
    public UnitTest1(Func<Owned<UserReponsitory>> userRepositoryFactory )
    {
        _userReponsitoryFactory = userReponsitoryFactory;
    }
    [Fact]
    public void Test1()
    {
        //using (var scoped = DbFixture.Container.Resolve<UserReponsitory>())
        //{
        //    var result = (scoped.GetAll()).ToList().Count();
        //    Assert.Equal(2, result);
        //}

        using (var scoped = userReponsitoryFactory())
        {
            var result = (scoped.Value.GetAll()).ToList().Count();
            Assert.Equal(2, result);
        }
    }
}
}

Func 是一个允许你返回 Owned 的工厂。 Owned 是一个容器,允许您自行处理对象(using 块)


0
投票

使用带有 XUnit 的 autofac 构造函数注入(以友好的方式)是可能的。

对于 XUnit 依赖注入,一般使用 Xunit.DependencyInjection 库。这允许您在

ConfigureHost
方法中配置服务注册。

然后你可以这样配置你的autofac容器:

    public class Startup
    {
        public void ConfigureHost(IHostBuilder hostBuilder) =>
            hostBuilder
                .ConfigureHostConfiguration(builder => { })
                .UseServiceProviderFactory(new AutofacServiceProviderFactory())
                .ConfigureContainer<ContainerBuilder>(builder =>
                {
                    //autofac registrations
                    builder.RegisterType<Repository>().As<IRepository>();
                });
    }

随时将

IRepository
注入您的测试课程。

    public class SampleTests
    {
        private readonly IRepository _repository;

        public SampleTests(IRepository repository)
        {
            _repository = repository;
        }

        [Fact]
        public async Task Loaded_data_from_injected_repository_is_not_empty()
        {
            var data = _repository.LoadSomething();
            Assert.IsNotEmpty(data);
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.