使用 NUnit 模拟 EF 的 ExecuteSqlCommand

Mocking EF's ExecuteSqlCommand using NUnit

我正在使用 Entity framework 内核。我指的是此处建议的代码之一:

public void SaveOrUpdate(MyEntity entity)
{
    var sql =  @"MERGE INTO MyEntity
                USING 
                (
                   SELECT   @id as Id
                            @myField AS MyField
                ) AS entity
                ON  MyEntity.Id = entity.Id
                WHEN MATCHED THEN
                    UPDATE 
                    SET     Id = @id
                            MyField = @myField
                WHEN NOT MATCHED THEN
                    INSERT (Id, MyField)
                    VALUES (@Id, @myField);"

    object[] parameters = {
        new SqlParameter("@id", entity.Id),
        new SqlParameter("@myField", entity.myField)
    };
    context.Database.ExecuteSqlCommand(sql, parameters);
}

我需要模拟 ExecuteSqlCommand 但此扩展方法不允许被 Moq 设置覆盖。我不想模拟整个方法 SaveOrUpdate。 请建议是否有任何方法可以使用任何数据库上下文方法模拟或设置它以进行单元测试。我正在使用 UseInMemoryDatabase 进行单元测试数据库上下文。

您需要模拟您的方法而不是 EF 核心实现。您可以使您的方法虚拟化并使用 Moq 模拟它的实现:

public virtual void SaveOrUpdate(MyEntity entity)
{
    var sql =  @"MERGE INTO MyEntity
                USING 
                (
                   SELECT   @id as Id
                            @myField AS MyField
                ) AS entity
                ON  MyEntity.Id = entity.Id
                WHEN MATCHED THEN
                    UPDATE 
                    SET     Id = @id
                            MyField = @myField
                WHEN NOT MATCHED THEN
                    INSERT (Id, MyField)
                    VALUES (@Id, @myField);"

    object[] parameters = {
        new SqlParameter("@id", entity.Id),
        new SqlParameter("@myField", entity.myField)
    };
    context.Database.ExecuteSqlCommand(sql, parameters);
}

然后模拟这个方法的实现。

查看以下帖子:

https://entityframework.net/knowledge-base/26014969/how-to-moq-entity-framework-sqlquery-calls

How to Moq Entity Framework SqlQuery calls

我非常喜欢这里的建议:Moq Entity Frameworks ExecuteSQLCommand。这并不是真正模拟整个函数,而是模拟 ExecuteSqlCommand,方法是在您的上下文中添加一个包装器:

所以在你的上下文中 class

public class MyContext : 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);
    }

    // The rest of the implementation

所以现在您可以模拟上下文,并且由于函数是虚拟的,您也可以模拟它们。您只需要像这样更改代码:

public void SaveOrUpdate(MyEntity entity)
{
    var sql =  @"MERGE INTO MyEntity
                USING 
                (
                   SELECT   @id as Id
                            @myField AS MyField
                ) AS entity
                ON  MyEntity.Id = entity.Id
                WHEN MATCHED THEN
                    UPDATE 
                    SET     Id = @id
                            MyField = @myField
                WHEN NOT MATCHED THEN
                    INSERT (Id, MyField)
                    VALUES (@Id, @myField);"

    object[] parameters = {
        new SqlParameter("@id", entity.Id),
        new SqlParameter("@myField", entity.myField)
    };
    context.ExecuteSqlCommand(sql, parameters);
}