【问题标题】:NSubstitute and AsQuerable not returning resultsNSubstitute 和 AsQuerable 不返回结果
【发布时间】:2020-09-08 12:17:31
【问题描述】:

我有一个奇怪的问题。 我正在创建一个泛型类,并且我有一个泛型方法和测试。测试如下:

[Test]
public async Task ReturnGeneric()
{
    // Assemble
    const int id = 1;
    var request = new GetGeneric<Venue>(id);
    var services = GetGenericContext.GivenServices();
    var handler = services.WhenCreateHandler();
    var venues = Builder<Venue>.CreateListOfSize(20).Build().ToDbSet();

    services.DatabaseContext.Set<Venue>().Returns(venues);

    // Act
    var response = await handler.Handle(request, CancellationToken.None);

    // Assert
    response.Success.Should().BeTrue();
    response.Error.Should().BeNull();
    response.Result.Should().BeOfType<Venue>();
}

}

方法如下:

public async Task<Attempt<T>> Handle(GetGeneric<T, TKey> request, CancellationToken cancellationToken)
{
    var id = request.Id;
    if (EqualityComparer<TKey>.Default.Equals(id, default)) return ValidationError.Required(nameof(id));

    var generics = _databaseContext.Set<T>().AsQueryable();
    var t = _databaseContext.Set<T>().ToList();
    var generic = generics.SingleOrDefault(m => m.Id.Equals(request.Id));
    var x = t.SingleOrDefault(m => m.Id.Equals(id));

    if (generic == null) return NotFoundError.ItemNotFound(nameof(T), request.Id.ToString());

    return generic;
}

变量tx 只是测试我自己的理智。 这里的问题是generic 在我的测试中为空,但x 不是。 AsQueryable() 方法似乎有问题。出于某种原因,如果我调用AsQueryable(),则集合中没有结果,但如果调用ToList(),则有。

这是我对ToDbSet()的扩展方法:

public static class DbSetExtensions
{
    public static DbSet<T> ToDbSet<T>(this IEnumerable<T> data) where T : class
    {
        var queryData = data.AsQueryable();
        var dbSet = Substitute.For<DbSet<T>, IQueryable<T>>();

        ((IQueryable<T>)dbSet).Provider.Returns(queryData.Provider);
        ((IQueryable<T>)dbSet).Expression.Returns(queryData.Expression);
        ((IQueryable<T>)dbSet).ElementType.Returns(queryData.ElementType);
        ((IQueryable<T>)dbSet).GetEnumerator().Returns(queryData.GetEnumerator());

        return dbSet;
    }
}

谁能想到这不起作用的原因?


整个类是这样的:

public class GenericGet<T, TKey> : IRequest<Attempt<T>> where T: TClass<TKey>
{
    public TKey Id { get; }

    public GenericGet(TKey id)
    {
        Id = id;
    }
}

public class GenericGet<T> : GenericGet<T, int> where T : TClass<int>
{
    public GenericGet(int id) : base(id)
    {
    }
}

public class GenericGetHandler<T, TKey> : IRequestHandler<GenericGet<T, TKey>, Attempt<T>> where T: TClass<TKey>
{
    private readonly DatabaseContext _databaseContext;

    public GenericGetHandler(DatabaseContext databaseContext)
    {
        _databaseContext = databaseContext;
    }

    public async Task<Attempt<T>> Handle(GenericGet<T, TKey> request, CancellationToken cancellationToken)
    {
        var id = request.Id;
        if (EqualityComparer<TKey>.Default.Equals(id, default)) return ValidationError.Required(nameof(id));

        var generics = _databaseContext.Set<T>().AsQueryable();
        var generic = generics.SingleOrDefault(m => m.Id.Equals(request.Id));

        if (generic == null) return NotFoundError.ItemNotFound(nameof(T), request.Id.ToString());

        return generic;
    }
}

public class GenericGetHandler<T> : GenericGetHandler<T, int> where T : TClass<int>
{
    public GenericGetHandler(DatabaseContext databaseContext) : base(databaseContext)
    {
    }
}

一个场地是这样的:

public class Venue: TClass<int>
{
    [Required, MaxLength(100)] public string Name { get; set; }
    [MaxLength(255)] public string Description { get; set; }

    public IList<Theatre> Theatres { get; set; }
}

【问题讨论】:

  • 测试有request类型GetGeneric&lt;Venue&gt;,但代码使用GetGeneric&lt;T, TKey&gt;?确保为T 传递的类型与被存根的类型相同(我写了an old example 说明这会如何导致问题。不确定这里是否是这种情况,但值得检查)。
  • 啊,是的,我应该把全班都贴出来
  • 不要模拟 DbContext,尽可能使用 InMemory 提供程序,或者针对实际数据库进行测试。

标签: c# generics nsubstitute


【解决方案1】:

我更改了我的 DatabaseContext 模拟,以实际使用 Fabio 建议的内存提供程序。 它看起来像这样:

public class DatabaseContextContext
{
    public DatabaseContext DatabaseContext;
    protected DatabaseContextContext()
    {
        var options = new DbContextOptionsBuilder<DatabaseContext>()
            .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
            .EnableSensitiveDataLogging()
            .Options;

        DatabaseContext = new DatabaseContext(options);
    }
}

然后我的 GetGenericContext 看起来像这样:

public class GenericGetContext<T> : DatabaseContextContext where T : TClass<int>
{
    public static GenericGetContext<T> GivenServices() => new GenericGetContext<T>();

    public GenericGetHandler<T> WhenCreateHandler() => new GenericGetHandler<T>(DatabaseContext);
}

而不是做:

services.DatabaseContext.Set<Venue>().Returns(venues);

我们不再嘲笑,所以我们实际上可以这样做:

services.DatabaseContext.Venues.AddRange(venues);
services.DatabaseContext.SaveChanges();

我们必须调用保存更改,否则它实际上不会向集合说明场所。 一旦你这样做了,一切都会按预期进行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-15
    • 2019-06-18
    相关资源
    最近更新 更多