【问题标题】:How to mock a base method in a derived class?如何模拟派生类中的基方法?
【发布时间】:2019-08-13 21:54:27
【问题描述】:

我想mock下面代码的方法base.Generate(operation, model, builder, false);

public class ExtendedSqlServerMigrationsSqlGenerator : SqlServerMigrationsSqlGenerator
    {
        public ExtendedSqlServerMigrationsSqlGenerator(MigrationsSqlGeneratorDependencies dependencies, IMigrationsAnnotationProvider migrationsAnnotations) :base(dependencies, migrationsAnnotations){}

        // this methode should be tested 
        protected override void Generate(CreateIndexOperation operation, IModel model, MigrationCommandListBuilder builder, bool terminate)
        {
            base.Generate(operation, model, builder, false); // this line should be mocked
            AddIncludeIndex(operation, builder, terminate);
        }
        protected void AddIncludeIndex(CreateIndexOperation operation, MigrationCommandListBuilder builder, bool terminate)
        {
            //some code
        }
        public void GenerateTest(CreateIndexOperation operation, IModel model, MigrationCommandListBuilder builder, bool terminate)
        {
            Generate(operation, model, builder, terminate);
        }

我使用的模拟设置是:

var sut = new Mock<ExtendedSqlServerMigrationsSqlGenerator>(GetDependencies(), p2.Object) 
{ 
 CallBase = true 
};
sut.Protected().Setup("Generate", true, ItExpr.IsAny<CreateIndexOperation>(), ItExpr.IsAny<IModel>(), ItExpr.IsAny<MigrationCommandListBuilder>(), ItExpr.IsAny<bool>());
sut.Object.GenerateTest(createIndexOperation.Object, new Model(), m3.Object, false);

目前我打电话给GenerateTest()。 问题是 Generated 方法被模拟而不是 base.Generate 我还尝试设置派生的 TestClass,它允许我从 testclass 调用受保护的方法。但同样的问题。

这与Mocking a protected member without reflection 不同。我知道如何模拟对基类方法的调用,但不知道如何模拟相同的方法。

关于这个类的一些背景信息

EF 可以基于 Model 生成 SQL 语句。为了扩展生成的 SQL,我将 DI 中的这个类替换为派生类。当 EF 调用 generate 时,我必须调用基类并添加一些额外的 SQL 语句。

我想模拟 `base.generate' 的原因是

  • 配置有效参数并不容易
  • 我对基类的实现细节不感兴趣。

这种情况似乎不是唯一的,并且期望有一种简单的方法来模拟它。

【问题讨论】:

  • 我有点困惑,为什么你要开始模拟基类中的实现。如果您正确地模拟了 Generate 方法的实现,则根本不应调用基类 Generate 方法。我错了吗?
  • 我在代码中添加了一些注释,我想测试哪个方法以及应该模拟哪个基本调用。让这一点更清楚。
  • 嗯.. 所以我问自己的问题是,这是否是 Mock 旨在帮助您解决的问题。该框架可帮助您删除依赖项,但在这种情况下,您正在尝试删除对基类的依赖项,这只是一个让我难以理解的奇怪概念,尤其是如果/因为 base.Generate() 方法有边效果。但与此同时,我知道在某些情况下,基本方法会进行您宁愿避免的系统调用..
  • 看看this SO post的第二个答案。我认为这部分反映了我在这里的感受。我的直觉反应是,由于您在实践中会看到所有副作用,最好使用 LocalDb 运行集成测试

标签: c# moq


【解决方案1】:

虽然我认为您尝试解决的问题在广义上非常有效,尤其是当基类进行您想要避免的系统/IO 调用时,我会指出 this previous related question 中的回复建议 Moq 不是这里的正确工具。

Moq 旨在从您的 sut 中删除依赖项,而不是替换其中的功能。这是有道理的,因为 sut 中的函数通常会产生副作用(尤其是当您尝试替换的函数的返回类型为 void 时)。

从历史上看,当我使用 EF 进行这种性质的测试时,我发现为每个测试类(或测试程序集)启动一个 localDb 并执行集成测试而不是为了进行单元测试而更加方便和可靠的单元测试。当然,这里有一些依赖项,您将代码优先用于迁移等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-16
    • 1970-01-01
    • 2013-04-11
    相关资源
    最近更新 更多