我正在用 Autofac 实现 Xunit,我可以通过下面的代码让它工作:
using (var scoped = DbFixture.Container.Resolve<UserReponsitory>())
{
var result = (scoped.GetAll()).ToList().Count();
Assert.Equal(2, result);
}
但是我想将 UserReponsitory 注入到测试方法中,而不是使用
DbFixture.Container.Resolve
。是否可以使以下代码工作?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;
}
换句话说,我怎么能依赖注入单元测试类?
任何帮助将不胜感激。
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 启动整个应用程序。
如果您已经在单元测试中启用了构造函数注入,那么您就快完成了。在测试的构造函数中,注入 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 块)
使用带有 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);
}
}