簡體   English   中英

在 Web api 2 的集成測試中使用 Autofac

[英]Using Autofac in integration tests with web api 2

我一直在我的集成測試中手動實例化我的服務,但是當我到達一個具有惰性依賴項的服務時,我做了一些研究,發現在進行測試時您實際上可以使用 Autofac 來解決您的服務

所以,我寫了這個類:

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.Integration.Owin
  • Autofac.Integration.WebApi
  • Autofac.Integration.WebApi.Owin

這些是在定義我的模塊時使用的相同引用,但這沒有幫助。 有誰知道我需要做什么才能讓它發揮作用?

我找不到合適的(簡單的)解決方案。 我看到有些人自己創建生命周期范圍,對我來說這似乎有點矯枉過正,而且不是“好”的代碼。 因此,采用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);
    }
}

這應該可以幫助其他有同樣問題的人。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM