在大型依赖对象图上注入mock
本文关键字:注入 mock 对象图 大型 依赖 | 更新日期: 2023-09-27 18:13:32
对于我想要测试的对象,我有一个相当重要的依赖关系图。解决依赖关系而不需要到处注册mock的最简单方法是什么?
例如,我有一个这样的依赖关系图:
PublicApi
ApiService
AccountingFacade
BillingService
BillingValidation
BillingRepository
UserService
UserRepository
我想测试PublicApi.CreateUser()
,我想让它运行所有代码,但我想模拟存储库,这样我就不必向数据库写入任何内容。我是否应该只使用DI容器并注册所有服务,用mock替换存储库,然后解析PublicApi
并运行该方法?
我正在查看AutoFixture,它看起来可能能够处理这样的事情,但我不能完全理解整个"冻结"与"注册"以及它与Moq的集成。
对于unittest,你应该只模拟直接依赖。在您的示例中,您创建PublicApi
并为ApiService
注入模拟,并验证PublicApi
是否在ApiService
模拟上使用正确的值调用了适当的方法。
用同样的方法测试从更深的依赖中分离出来的所有其他组件。
如果你想测试几个组件的组合,那就不是单元测试,而是集成测试。因此,这取决于你如何把你的类放在一起。例如,如果您正在使用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>();
尽管你必须问自己,你在这里测试什么?如果只是相互作用,我就会像我第一次提到的那样做,如果是更多,那就考虑后一种选择。不管怎样,我希望它能给你一些选择。