亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

調用EF Core擴展方法的c#單元測試方法

調用EF Core擴展方法的c#單元測試方法

C#
精慕HU 2021-07-01 13:00:16
我一直在嘗試對這個簡單的方法進行單元測試:public void DeleteAllSettingsLinkedToSoftware(Guid softwareId){    _dbContext.Settings.Where(s => s.SoftwareId == softwareId).ForEachAsync(s => s.IsDeleted = true);    _dbContext.SaveChanges();}但是,從ForEachAsync()調用該方法的那一刻起,我就很難對其進行單元測試。到目前為止,我已經使用 Moq 來設置 dbContext 以在Where()執行時返回正確的設置。我的嘗試:Setup(m => m.ForEachAsync(It.IsAny<Action<Setting>>(), CancellationToken.None));我的問題是:我將如何對該ForEachAsync()方法的調用進行單元測試?我在網上讀到有人說不可能對一些靜態方法進行單元測試,如果在我的情況下是這樣,我很好奇盡可能多地測試這種方法的替代方法。編輯我的完整測試代碼:[TestMethod]public async Task DeleteAllSettingsLinkedToSoftware_Success(){    //Arrange    var settings = new List<Setting>    {        new Setting        {            SoftwareId = SoftwareId1        },        new Setting        {            SoftwareId = SoftwareId1        },        new Setting        {            SoftwareId = SoftwareId1        },        new Setting        {            SoftwareId = SoftwareId2        }    }.AsQueryable();    var queryableMockDbSet = GetQueryableMockDbSet(settings.ToList());    queryableMockDbSet.As<IQueryable<Setting>>()        .Setup(m => m.Provider)        .Returns(new TestDbAsyncQueryProvider<Setting>(settings.Provider));    DbContext.Setup(m => m.Settings).Returns(queryableMockDbSet.Object);    _settingData = new SettingData(DbContext.Object, SettingDataLoggerMock.Object);    //Act    var result = await _settingData.DeleteAllSettingsLinkedToSoftwareAsync(SoftwareId1);    //Assert    DbContext.Verify(m => m.Settings);    DbContext.Verify(m => m.SaveChanges());    Assert.AreEqual(4, DbContext.Object.Settings.Count());    Assert.AreEqual(SoftwareId2, DbContext.Object.Settings.First().SoftwareId);}
查看完整描述

1 回答

?
喵喵時光機

TA貢獻1846條經驗 獲得超7個贊

你根本不必嘲笑ForEachAsync。ForEachAsync返回Task并異步執行這是您的問題的根源。


使用async和await鍵來解決您的問題:


public async void DeleteAllSettingsLinkedToSoftware(Guid softwareId)

{

    await _dbContext.Settings.Where(s => s.SoftwareId == softwareId)

                             .ForEachAsync(s => s.IsDeleted = true);

    _dbContext.SaveChanges();  

}

編輯:


出現新異常是因為提供Provider的不是IDbAsyncQueryProvider。


Microsoft 實現了此接口的通用版本:TestDbAsyncQueryProvider<TEntity>. 這是鏈接中的實現:


internal class TestDbAsyncQueryProvider<TEntity> : IDbAsyncQueryProvider 

    private readonly IQueryProvider _inner; 


    internal TestDbAsyncQueryProvider(IQueryProvider inner) 

    { 

        _inner = inner; 

    } 


    public IQueryable CreateQuery(Expression expression) 

    { 

        return new TestDbAsyncEnumerable<TEntity>(expression); 

    } 


    public IQueryable<TElement> CreateQuery<TElement>(Expression expression) 

    { 

        return new TestDbAsyncEnumerable<TElement>(expression); 

    } 


    public object Execute(Expression expression) 

    { 

        return _inner.Execute(expression); 

    } 


    public TResult Execute<TResult>(Expression expression) 

    { 

        return _inner.Execute<TResult>(expression); 

    } 


    public Task<object> ExecuteAsync(Expression expression, CancellationToken cancellationToken) 

    { 

        return Task.FromResult(Execute(expression)); 

    } 


    public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken) 

    { 

        return Task.FromResult(Execute<TResult>(expression)); 

    } 


internal class TestDbAsyncEnumerable<T> : EnumerableQuery<T>, IDbAsyncEnumerable<T>, IQueryable<T> 

    public TestDbAsyncEnumerable(IEnumerable<T> enumerable) 

        : base(enumerable) 

    { } 


    public TestDbAsyncEnumerable(Expression expression) 

        : base(expression) 

    { } 


    public IDbAsyncEnumerator<T> GetAsyncEnumerator() 

    { 

        return new TestDbAsyncEnumerator<T>(this.AsEnumerable().GetEnumerator()); 

    } 


    IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator() 

    { 

        return GetAsyncEnumerator(); 

    } 


    IQueryProvider IQueryable.Provider 

    { 

        get { return new TestDbAsyncQueryProvider<T>(this); } 

    } 


internal class TestDbAsyncEnumerator<T> : IDbAsyncEnumerator<T> 

    private readonly IEnumerator<T> _inner; 


    public TestDbAsyncEnumerator(IEnumerator<T> inner) 

    { 

        _inner = inner; 

    } 


    public void Dispose() 

    { 

        _inner.Dispose(); 

    } 


    public Task<bool> MoveNextAsync(CancellationToken cancellationToken) 

    { 

        return Task.FromResult(_inner.MoveNext()); 

    } 


    public T Current 

    { 

        get { return _inner.Current; } 

    } 


    object IDbAsyncEnumerator.Current 

    { 

        get { return Current; } 

    } 

現在Setup你必須像這樣使用它:


mockSet.As<IQueryable<Setting>>() 

       .Setup(m => m.Provider) 

       .Returns(new TestDbAsyncQueryProvider<Setting>(data.Provider)); 


查看完整回答
反對 回復 2021-07-17
  • 1 回答
  • 0 關注
  • 293 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號