Moq实体框架ExecuteSQLCommand

时间:2014-10-30 22:27:33

标签: c# entity-framework moq

我读过在使用moq时你无法模拟非虚函数。我现在也读到这应该是可能的..这是真的吗? 如果是这样,那么我想模拟以下查询:

DatabaseContext.Database.ExecuteSqlCommand(updateQuery, newValue);

我在我的测试中覆盖了上下文

DAL.Context.DatabaseContext = mockContext.Object;

我已尝试过此设置,但似乎查询仍然是我的常规数据库

mockContext.Setup(c => c.Set<AppSalesAndResult>()).Returns(mockBudgetData.Object);

任何想法,也许executeccommand可能被其他东西替换,以便上面的行可以捕获任何udpates到集合?我一次更新多行时由于性能原因使用executionqlcommand。常规EF太慢

更新:

阅读以下帖子,How to Moq Entity Framework SqlQuery calls我想知道类似的实现是否适用于ExecuteSQLCommand ......

2 个答案:

答案 0 :(得分:3)

我能做的是模拟ExecuteSqlCommand,这在DataBase类中是不可能做的,是在我的DbContext继承中创建相同的方法,但这次是虚拟的,并调用Database.ExecuteSqlCommand

public class MyDbContext : DbContext
{
    public virtual int ExecuteSqlCommand(string sql, params object[] parameters)
    {
        return Database.ExecuteSqlCommand(sql, parameters);
    }
    public virtual int ExecuteSqlCommand(TransactionalBehavior transactionalBehavior, string sql, params object[] parameters)
    {
        return Database.ExecuteSqlCommand(transactionalBehavior, sql, parameters);
    }

然后我更改了我的业务代码以调用此创建的方法(非数据库方法):

DatabaseContext.ExecuteSqlCommand(updateQuery, newValue);

然后,它的工作原理

答案 1 :(得分:0)

可以模拟ExecuteSqlCommand。但是,这并不简单。

作为扩展方法,您必须模拟内部结构。最终创建一个RawSqlCommand并在ExecuteNonQuery上调用IRelationalCommand。扩展方法会创建新的对象来完成实际工作,并且由于RawSqlCommandDatabaseFacade没有接口,因此变得更加复杂,您必须模拟具体的类。

我最终写了EntityFrameworkCore.DbContextBackedMock.Moq,因为周围没有其他东西可以完成所有模拟(FromSql,ExecuteSqlCommand,DbQuery,内存提供程序无法做到的关系性东西)。当涉及到模拟时,可以节省一些时间,如果我正在寻找的话,我肯定会使用现有的软件包。

如果您想自己动手制作ExecuteSqlCommand的模拟设置,则如下所示:

var relationalCommand = new Mock<IRelationalCommand>();
relationalCommand.Setup(m => m.ExecuteNonQuery(It.IsAny<IRelationalConnection>(), It.IsAny<IReadOnlyDictionary<string, object>>())).Returns(() => expectedResult);

var rawSqlCommand = new Mock<RawSqlCommand>(MockBehavior.Strict, relationalCommand.Object, new Dictionary<string, object>());
rawSqlCommand.Setup(m => m.RelationalCommand).Returns(() => relationalCommand.Object);
rawSqlCommand.Setup(m => m.ParameterValues).Returns(new Dictionary<string, object>());

var rawSqlCommandBuilder = new Mock<IRawSqlCommandBuilder>();
rawSqlCommandBuilder.Setup(m => m.Build(It.IsAny<string>(),  It.IsAny<IEnumerable<object>>())).Returns(rawSqlCommand.Object);

var databaseFacade = new Mock<DatabaseFacade>(MockBehavior.Strict, _dbContextToMock);
databaseFacade.As<IInfrastructure<IServiceProvider>>().Setup(m => m.Instance.GetService(It.Is<Type>(t => t == typeof(IConcurrencyDetector)))).Returns(new Mock<IConcurrencyDetector>().Object);
databaseFacade.As<IInfrastructure<IServiceProvider>>().Setup(m => m.Instance.GetService(It.Is<Type>(t => t == typeof(IRawSqlCommandBuilder)))).Returns(rawSqlCommandBuilder.Object);
databaseFacade.As<IInfrastructure<IServiceProvider>>().Setup(m => m.Instance.GetService(It.Is<Type>(t => t == typeof(IRelationalConnection)))).Returns(new Mock<IRelationalConnection>().Object);

_dbContextMock.Setup(m => m.Database).Returns(databaseFacade.Object);

expectedResult是ExecuteSqlCommand查询应在完成时返回的预期整数。您可以使用回调来应用sql命令对数据源执行的任何操作。

此外,还可以设置与sql和指定参数的模拟匹配,但是这会使已经涉及的设置更加复杂。如果您想查看此设置匹配的有效示例,请查看DbContextMockBuilder AddExecuteSqlCommandResult方法。