【问题标题】:The source IQueryable doesn't implement IDbAsyncEnumerable when trying to mock尝试模拟时,源 IQueryable 未实现 IDbAsyncEnumerable
【发布时间】:2019-02-09 07:13:06
【问题描述】:

我正在尝试测试我拥有的一些代码:

public async Task<Sortation> SaveAsync(Sortation sortation)
{
    if (sortation.Id == 0)
    {
        var sortations = await ListAsync(sortation.CategoryId);
        sortation.Order = sortations.Count;
        _sortationService.Create(sortation);
    }
    else
    {
        _sortationService.Update(sortation);
    }

    await _sortationService.SaveChangesAsync();

    return sortation;
}

ListAsync 方法给我带来了问题。 我这样设置我的测试:

[Test]
public async Task ShouldHaveOrderOfZero()
{
    // Assemble
    const string categoryId = "cameras";
    var services = SortationContext.GivenServices();
    var sortationProvider = services.WhenGetSortationProvider();
    var sortations = new List<Sortation>();
    var sortation = new Sortation { CategoryId = categoryId };

    services.MockSortationService.Setup(x => x.List()).Returns(sortations.AsQueryable);

    // Act
    await sortationProvider.SaveAsync(sortation);

    // Assert
    sortation.Order.Should().Be(0);
}

当我运行它时,我得到了这个错误:

消息:System.InvalidOperationException:源 IQueryable 未实现 IDbAsyncEnumerable。只有实现 IDbAsyncEnumerable 的源才能用于实体框架异步操作。

据此:Only sources that implement IAsyncEnumerable can be used for Entity Framework asynchronous operations 我需要将 EF 添加到我的 UnitTest 项目中,我这样做了。 但错误仍然存​​在。

ListAsync 方法如下所示:

public async Task<List<Sortation>> ListAsync(string categoryId, params string[] includes) => 
    await _sortationService.List(includes).Where(m => m.CategoryId.Equals(categoryId)).ToListAsync();

有谁知道我怎样才能阻止这个错误的发生?

【问题讨论】:

  • 坦率地说,像 EF 这样的 ORM 并不适合模拟和单元测试;我也认为,即使它是:DAL 代码的单元测试只是没有用(它给人一种非常错误的安全感,直截了当对我的口味几乎毫无用处 - 尽管是主观的) - 我会方式对这里的集成测试更感兴趣,但这意味着:没有模拟
  • 您能否展示更多正在测试的提供程序类。包括依赖项。你可能有一个泄漏的抽象。

标签: c# entity-framework unit-testing nunit moq


【解决方案1】:

在我的情况下,异常是由使用错误的 ToListAsync 扩展引起的。

它来自:

使用 System.Data.Entity; 而不是

使用 Microsoft.EntityFrameworkCore; 更改命名空间修复了错误。

【讨论】:

    【解决方案2】:

    不知道问题是否仍然存在,但仍然存在。我同意马克的评论,但这里有一个例子,对我有用。我为提到的类添加了一些合理的存根实现,因为没有足够的细节问题。我的假设可能是错误的:

    [Test]
    public async Task ShouldHaveOrderOfZero()
    {
        // Assemble
        const string categoryId = "cameras";
        var services = SortationContext.GivenServices();
        var sortationProvider = services.WhenGetSortationProvider();
        var sortations = new List<Sortation>();
        var sortation = new Sortation { CategoryId = categoryId };
    
        // the key moq configuration here
        services.MockSortationService.Setup(x => x.ListAsync(It.IsAny<string>())).Returns(Task.FromResult(sortations));
    
        // Act
        await sortationProvider.SaveAsync(sortation);
    
        // Assert
        sortation.Order.Should().Be(0);
    }
    
    public class SortationProvider
    {
        private SortationService _sortationService;
    
        public SortationProvider()
        {
            _sortationService = new SortationService();
        }
    
        public async Task<Sortation> SaveAsync(Sortation sortation)
        {
            if (sortation.Id == 0)
            {
                var sortations = await ListAsync(sortation.CategoryId);
                sortation.Order = sortations.Count;
                _sortationService.Create(sortation);
            }
            else
            {
                _sortationService.Update(sortation);
            }
    
            await _sortationService.SaveChangesAsync();
    
            return sortation;
        }
    
        // should be virtual
        public virtual async Task<List<Sortation>> ListAsync(string categoryId, params string[] includes) =>
            await _sortationService.List(includes).Where(m => m.CategoryId.Equals(categoryId)).ToListAsync();
    
    }
    
    public class SortationContext
    {
        public static Services GivenServices()
        {
            return new Services();
        }
    }
    
    public class Services
    {
        public Services()
        {
            MockSortationService = new Mock<SortationProvider>();
        }
    
        public SortationProvider WhenGetSortationProvider()
        {
            return MockSortationService.Object;
        }
    
        public Mock<SortationProvider> MockSortationService { get; set; }
    }
    
    internal class SortationService
    {
        public void Create(Sortation sortation)
        {
    
        }
    
        public void Update(Sortation sortation)
        {
    
        }
    
        public Task SaveChangesAsync()
        {
            return Task.CompletedTask;
        }
    
        public DbSet<Sortation> List(string[] includes)
        {
            throw new NotImplementedException();
        }
    }
    
    public class Sortation
    {
        public string CategoryId { get; set; }
        public int Id { get; set; }
        public int Order { get; set; }
    }
    

    主要变化在于包含Setup 方法的行。我也将ListAsync 方法设为虚拟。主要假设是List(string[] includes) 方法返回DbSet&lt;Sortation&gt;。希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-05
      • 1970-01-01
      • 1970-01-01
      • 2021-02-11
      • 2011-10-26
      • 2021-01-02
      • 1970-01-01
      • 2018-12-04
      相关资源
      最近更新 更多