我想模拟以下代码的方法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 调用受保护的方法。但也有同样的问题。
这与在没有反射的情况下嘲笑受保护的成员不同。我知道如何模拟对基类方法的调用,但不知道如何模拟相同的方法。
有关此类的一些背景信息
EF 可以基于模型生成 SQL 语句。为了扩展生成的 SQL,我将 DI 中的这个类替换为派生类。当EF调用generate
时,我必须调用基类并添加一些额外的SQL语句。
我想嘲笑"base.generate"的原因是
- 配置有效参数并不容易
- 我对基类的实现细节不感兴趣。
这种情况似乎并不独特,并且期望有一种简单的方法来模拟这种情况。
虽然我认为您试图解决的问题在广义上非常有效,尤其是当基类进行您想要避免的系统/IO 调用时,我会指出之前相关问题中的回答,以表明 Moq 不是这里的正确工具。
Moq 旨在从您的 sut 中删除依赖项,而不是替换其中的功能。这是有道理的,因为 sut 中的函数通常会有副作用(尤其是当您尝试替换的函数的返回类型为 void 时)。
从历史上看,当我使用 EF 进行这种性质的测试时,我发现为每个测试类(或测试程序集)启动 localDb 并执行集成测试比为了单元测试而尝试单元测试更方便、更可靠。当然,这里有一些依赖项,您在迁移等方面使用代码优先。