簡體   English   中英

System.Not Supported 用於模擬 ExecuteSQLCommand Moq Entity Framework Core 的異常

[英]System.Not Supported exception for mocking ExecuteSQLCommand Moq Entity Framework Core

我正在嘗試為我的數據庫層中的方法編寫單元測試。 我在context.Setup for ExecuteSqlCommand遇到錯誤:

System.NotSupportedException: '不支持的表達式:... => .... ExecuteSqlCommand((RawSqlString)It.IsAny<string>(), It.IsAny<object[]>())擴展方法(此處:RelationalDatabaseFacadeExtensions.ExecuteSqlCommand ) 不能用於設置/驗證表達式。

我的方法是這樣的:

public void InsertIntoQueue()
{           
    context.Database
           .ExecuteSqlCommand(" EXEC SP_Name param1",
                              new SqlParameter("param1", param1.value));           
}

我的單元測試是這樣的:

[Fact]
[Trait("TestCategory", "Unit")]
public async void Test1_Ok()
{
    var context = new Mock<Context>();
    {
        context.Setup(x => x.Database.ExecuteSqlCommand(It.IsAny<string>(), It.IsAny<object[]>())).Returns(1);
        var repo = GetDBRepository(context.Object);
        repo.InsertIntoQueue();                
    }
}

有沒有辦法直接模擬ExecuteSQLCommand方法?

無法直接模擬它,因為它是一種擴展方法。

可以模擬該擴展方法調用的內容並間接模擬它。 我有一個類似的案例,最終實現了EntityFrameworkCore.Testing,因為它是一個非常復雜的 Moq 設置。

var relationalCommandMock = new Mock<IRelationalCommand>();
relationalCommandMock
    .Setup(m => m.ExecuteNonQuery(It.IsAny<IRelationalConnection>(), It.IsAny<IReadOnlyDictionary<string, object>>()))
    .Returns((IRelationalConnection providedConnection, IReadOnlyDictionary<string, object> providedParameterValues) => executeSqlCommandResult);
relationalCommandMock
    .Setup(m => m.ExecuteNonQueryAsync(It.IsAny<IRelationalConnection>(), It.IsAny<IReadOnlyDictionary<string, object>>(), It.IsAny<CancellationToken>()))
    .Returns((IRelationalConnection providedConnection, IReadOnlyDictionary<string, object> providedParameterValues, CancellationToken providedCancellationToken) => Task.FromResult(executeSqlCommandResult));
var relationalCommand = relationalCommandMock.Object;

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

var rawSqlCommandBuilderMock = new Mock<IRawSqlCommandBuilder>();

rawSqlCommandBuilderMock
    .Setup(m => m.Build(It.IsAny<string>(), It.IsAny<IEnumerable<object>>()))
    .Returns((string providedSql, IEnumerable<object> providedParameters) => rawSqlCommand);

var rawSqlCommandBuilder = rawSqlCommandBuilderMock.Object;

var serviceProviderMock = new Mock<IServiceProvider>();
serviceProviderMock.Setup(m => m.GetService(It.Is<Type>(t => t == typeof(IConcurrencyDetector)))).Returns((Type providedType) => Mock.Of<IConcurrencyDetector>());
serviceProviderMock.Setup(m => m.GetService(It.Is<Type>(t => t == typeof(IRawSqlCommandBuilder)))).Returns((Type providedType) => rawSqlCommandBuilder);
serviceProviderMock.Setup(m => m.GetService(It.Is<Type>(t => t == typeof(IRelationalConnection)))).Returns((Type providedType) => Mock.Of<IRelationalConnection>());
var serviceProvider = serviceProviderMock.Object;

var databaseFacadeMock = new Mock<DatabaseFacade>(MockBehavior.Strict, mockedDbContext);
databaseFacadeMock.As<IInfrastructure<IServiceProvider>>().Setup(m => m.Instance).Returns(serviceProvider);
var databaseFacade = databaseFacadeMock.Object;

Mock.Get(mockedDbContext).Setup(m => m.Database).Returns(databaseFacade);

這是支持 ExecuteSqlCommand 和 ExecuteSqlCommandAsync 所需的設置。 executeSqlCommandResult是調用時要返回的整數結果。

請注意,我將模擬的 db 上下文傳遞給數據庫外觀模擬構造函數,然后在模擬數據庫上執行另一個 Moq 設置,我沒有這樣做,因為我已經在 DbContext 數據庫屬性上執行了設置作為模擬數據庫的一部分語境。 我已經觀察到內聯新實例的測試成功,所以我認為這並不重要,就我而言,我不想啟動另一個實例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM