【问题标题】:Using Autofac in integration tests with web api 2在与 web api 2 的集成测试中使用 Autofac
【发布时间】:2018-02-12 09:43:30
【问题描述】:

我一直在我的集成测试中手动实例化我的服务,但是当我得到一个具有 Lazy 依赖项的服务时,我做了一些研究并发现 you can actually use Autofac to resolve your services when doing your tests

所以,我写了这个类:

public class Container<TModule> where TModule: IModule, new()
{
    private readonly IContainer _container;

    protected Container()
    {
        var builder = new ContainerBuilder();
        builder.RegisterModule(new TModule());
        _container = builder.Build();
    }

    protected TEntity Resolve<TEntity>() => _container.Resolve<TEntity>();
    protected void Dispose() => _container.Dispose();
}

然后在我的上下文中,我改为:

public class ProductContext : Container<AutofacModule>
{
    public IProductProvider ProductProvider { get; }
    public static ProductContext GiventServices() => new ProductContext();

    protected ProductContext()
    {
        ProductProvider = Resolve<IProductProvider>();
    }

    public List<JObject> WhenListProducts(int categoryId) => ProductProvider.List(categoryId);
}

我有另一个似乎可以工作的上下文(测试通过),它正在使用 MatchProvider。如果我在我的 Autofac 模块中比较两者,它们看起来像这样:

builder.RegisterType<ProductProvider>().As<IProductProvider>().InstancePerRequest();

builder.RegisterType<MatchProvider>().As<IMatchProvider>().SingleInstance();

因为 MatchProvider 是一个单例,它似乎没有解决任何问题,但 ProductProvider 是每个请求的实例,这似乎是问题所在.

在运行任何需要该服务的测试时出现此错误:

从请求实例的范围中看不到带有匹配“AutofacWebRequest”标签的范围。

我认为这是因为我没有安装正确的 nuget 包。所以我安装了:

  • Autofac
  • Autofac.Integration.Owin
  • Autofac.Integration.WebApi
  • Autofac.Integration.WebApi.Owin

这些是在定义我的模块时使用的相同引用,但这没有帮助。 有谁知道我需要做什么才能让它工作?

【问题讨论】:

    标签: c# testing asp.net-web-api integration-testing autofac


    【解决方案1】:

    我找不到合适的(简单)解决方案。我看到有些人自己创建了生命周期范围,这对我来说似乎有点矫枉过正,而且它不是“好”的代码。 因此,采用 Autofac 的 原则之一: 任何多次注册的服务;最后一个实例是被解析的实例。

    所以在我的 Container 课程中,我只是将我的 InstancePerRequest 服务重新注册为 InstancePerDependency。这解决了我的问题。 这是我的完整代码:

    public class ContainerContext<TModule> where TModule: IModule, new()
    {
        private IContainer _container;
    
        protected ContainerContext()
        {
            var builder = new ContainerBuilder();
            builder.RegisterModule(new TModule());
    
            // Because Autofac will resolve services using the last registration, we can change all our web api 
            // services to by InstancePerDependency instead of InstancePerRequest which is obviously better
            // when testing.
            builder.RegisterType<AnswerProvider>().As<IAnswerProvider>().InstancePerDependency();
            builder.RegisterType<AttributeProvider>().As<IAttributeProvider>().InstancePerDependency();
            builder.RegisterType<CategoryProvider>().As<ICategoryProvider>().InstancePerDependency();
            builder.RegisterType<ClaimProvider>().As<IClaimProvider>().InstancePerDependency();
            builder.RegisterType<ClientProvider>().As<IClientProvider>().InstancePerDependency();
            builder.RegisterType<CriteriaProvider>().As<ICriteriaProvider>().InstancePerDependency();
            builder.RegisterType<FeedProvider>().As<IFeedProvider>().InstancePerDependency();
            builder.RegisterType<FormulaProvider>().As<IFormulaProvider>().InstancePerDependency();
            builder.RegisterType<ImageProvider>().As<IImageProvider>().InstancePerDependency();
            builder.RegisterType<GroupProvider>().As<IGroupProvider>().InstancePerDependency();
            builder.RegisterType<QuestionProvider>().As<IQuestionProvider>().InstancePerDependency();
            builder.RegisterType<StripeProvider>().As<IStripeProvider>().InstancePerDependency();
    
            builder.RegisterType<ApiAiProvider>().As<IApiAiProvider>().InstancePerDependency();
            builder.RegisterType<PiiikProvider>().As<IPiiikProvider>().InstancePerDependency();
            builder.RegisterType<ProductProvider>().As<IProductProvider>().InstancePerDependency();
            builder.RegisterType<SettingProvider>().As<ISettingProvider>().InstancePerDependency();
            builder.RegisterType<TrackingProvider>().As<ITrackingProvider>().InstancePerDependency();
    
            _container = builder.Build();
        }
    
        protected TEntity Resolve<TEntity>() => _container.Resolve<TEntity>();
        protected void Dispose() => _container.Dispose();
    }
    

    然后,我使用的任何上下文都会继承这个类:

    public class ProductContext : ContainerContext<AutofacModule>
    {
        public IProductProvider ProductProvider { get; }
        public static ProductContext GiventServices() => new ProductContext();
    
        protected ProductContext()
        {
            ProductProvider = Resolve<IProductProvider>();
        }
    
        public List<JObject> WhenListProducts(int categoryId) => ProductProvider.List(categoryId);
    }
    

    这意味着,在测试时,我可以这样做:

    [TestFixture]
    public class ProductProviderTests
    {
        [Test]
        public void ShouldHaveProducts()
        {
            var services = ProductContext.GiventServices();
            var products = services.WhenListProducts(1);
            products.Count.Should().NotBe(0);
        }
    
        [Test]
        public void ShouldHaveDuplicateVariants()
        {
            var services = ProductContext.GiventServices();
            var products = services.WhenListProducts(1);
            var anyDuplicate = products.GroupBy(x => x.SelectToken("variant").ToString()).Any(g => g.Count() > 1);
            anyDuplicate.Should().Be(true);
        }
    
        [Test]
        public void ShouldNotHaveDuplicateGtins()
        {
            var services = ProductContext.GiventServices();
            var products = services.WhenListProducts(1);
            var anyDuplicate = products.GroupBy(x => x.SelectToken("gtin").ToString()).Any(g => g.Count() > 1);
            anyDuplicate.Should().Be(false);
        }
    }
    

    这应该可以帮助遇到同样问题的其他人。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多