C# 在大型依赖对象图上注入mock

C# 在大型依赖对象图上注入mock,c#,unit-testing,dependency-injection,moq,autofixture,C#,Unit Testing,Dependency Injection,Moq,Autofixture,对于要测试的对象,我有一个相当重要的依赖关系图。解决依赖关系而不必到处注册mock的最简单方法是什么 例如,我有这样一个依赖关系图: PublicApi ApiService AccountingFacade BillingService BillingValidation BillingRepository UserService UserRepository 我想测

对于要测试的对象,我有一个相当重要的依赖关系图。解决依赖关系而不必到处注册mock的最简单方法是什么

例如,我有这样一个依赖关系图:

  PublicApi
    ApiService
      AccountingFacade
         BillingService
           BillingValidation
           BillingRepository
         UserService
           UserRepository
我想测试PublicApi.CreateUser(),我想让它运行所有代码,但我想模拟存储库,这样我就不必向数据库写入任何内容。我是否应该使用DI容器并注册所有服务,用mock替换存储库,然后解析
PublicApi
并运行该方法


我正在研究AutoFixture,它看起来可能能够处理类似的事情,但我不能完全理解“冻结”与“注册”以及它与Moq的集成。

对于单元测试,您应该只模拟直接依赖关系。在本例中,您创建
PublicApi
并为
ApiService
注入一个mock,并验证
PublicApi
是否使用
ApiService
mock上的正确值调用了适当的方法

以同样的方式测试与更深层依赖项隔离的所有其他组件


如果您想测试几个组件的组合,那不是单元测试,而是集成测试。因此,这取决于你是如何把你的类。e、 g.如果您使用的是IoC容器,它可能支持以某种方式替换存储库的配置。在这种情况下,您可以使用应用程序的配置,并用mock替换存储库和视图。

这可能一点也没有帮助,但我还是要说

似乎您试图一次测试太多,为什么不只测试BillingService->BillingValidation,然后测试BillingService->BillingRepository等等。这样,您将有一套测试来证明每个测试都有效,然后当您在PublicApi层时,您只需要模拟ApiService,因为您已经测试了它下面的所有内容,所以再次测试它没有任何价值

一般来说,我一次只测试一层,但我不知道你的完整场景,所以你可能有一些我没有解释的东西,所以如果是这种情况,你真的需要一起测试所有这些,我只会引入一个简单而轻量级的DI框架,比如Ninject之类的

通过这种方式,您可以将所有类型绑定到mock,然后从中实例化PublicApi

使用ninject时,它看起来像:

Kernel.Bind<UserRepository>.ToConst(YourMockUserRepositoryInstance);
Kernel.Bind<UserService>.ToConst(YourMockUserServiceInstance);
Kernel.Bind<BillingRepository>.ToConst(YourMockBillingRepositoryInstance);
Kernel.Bind<BillingValidation>.ToConst(YourMockBillingValidationInstance);
Kernel.Bind<BillingService>.ToConst(YourMockBillingServiceInstance);
Kernel.Bind<AccountingFacade>.ToConst(YourMockAccountingFacadeInstance);
Kernel.Bind<ApiService>.ToConst(YourMockApiServiceInstance);
Kernel.Bind<PublicApi>.ToSelf();

var publicApi = Kernel.Get<PublicApi>();
Kernel.Bind.ToConst(YourMockUserRepositoryInstance);
ToConst(YourMockUserServiceInstance);
ToConst(您的MockBillingRepositoryInstance);
ToConst(您的MockBillingValidationInstance);
Kernel.Bind.ToConst(您的MockBillingService实例);
ToConst(您的mockAccountingFacadeInstance);
ToConst(您的mockapiserviceinstance);
Kernel.Bind.ToSelf();
var publicApi=Kernel.Get();

尽管你不得不问自己,你在这里测试什么?如果只是互动,我会像我第一次提到的那样做,如果更多的话,也许会考虑后一种选择。不管怎样,我希望它能给你一些选择。

这是有道理的。我可以通过进行多层测试来获得全面的覆盖,而不是一次测试多个层。确切地说,这使测试本身更简单,更容易理解。