使用Autofac进行XUnit Test构造函数依赖注入

时间:2017-04-20 13:14:57

标签: asp.net-core autofac xunit2

我正在使用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;
        }

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

2 个答案:

答案 0 :(得分:1)

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

当您实施IClassFixture<DbFixture>接口时,xUnit在其构造函数中需要一个DbFixture参数,并且参数的类型取决于{{1} } T

话虽如此,当你强迫IClassFixture<T>时,你的构造函数必须看起来像IClassFixture<DbFixture>。但是你有public UnitTest1(DbFixture),所以xUnit不知道在那里注入什么。

您还可以实现多种IUserRepository类型,但每个测试类只能使用一次IClassFixture<T>

来自官方xUnit docs on shared contextT):

  

重要提示:xUnit.net使用接口IClassFixture&lt;&gt;的存在要知道你想要创建和清理类夹具。无论是否将类的实例作为构造函数参数,它都会执行此操作。 Simiarly,如果添加构造函数参数但忘记添加接口,xUnit.net会告诉您它不知道如何满足构造函数参数。

更新

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

IClassFixture<T>

然而,问题是使用它的好方法呢?不确定您想要达到什么目标,但如果您想进行单元测试,那么您不必在所有或具体类别中使用IoC容器,只需要模拟和您正在测试的类型。

如果你想在ASP.NET Core MVC / WebApi上进行集成测试,那么你应该使用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); } } 类,它将整个应用程序与你已经配置的所有IoC一起旋转。

答案 1 :(得分:0)

如果你已经在单元测试中启用了构造函数注入,那么你几乎已经完成了。在测试的构造函数中,注入一个

Func<Owned<UserReponsitory>>

e.g。

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是一个工厂,允许您返回自己的。拥有一个容器,允许您自己处理对象(使用块)