NSubstitute 和 AsQuerable 不返回结果
NSubstitute and AsQuerable not returning results
我有一个奇怪的问题。
我正在创建一个通用的 class 并且我有一个通用的方法和测试。测试看起来像这样:
[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;
}
变量t
和x
只是对我自己理智的测试。
这里的问题是 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;
}
}
谁能想出这不起作用的原因?
整个 class 看起来像这样:
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; }
}
我按照 Fabio 的建议更改了 DatabaseContext 模拟以实际使用内存提供程序。
它看起来像这样:
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();
我们必须调用save changes 否则它实际上不会说集合的地点。
一旦你这样做,一切都会按预期工作。
我有一个奇怪的问题。 我正在创建一个通用的 class 并且我有一个通用的方法和测试。测试看起来像这样:
[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;
}
变量t
和x
只是对我自己理智的测试。
这里的问题是 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;
}
}
谁能想出这不起作用的原因?
整个 class 看起来像这样:
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; }
}
我按照 Fabio 的建议更改了 DatabaseContext 模拟以实际使用内存提供程序。 它看起来像这样:
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();
我们必须调用save changes 否则它实际上不会说集合的地点。 一旦你这样做,一切都会按预期工作。