How to mock Nhibernate .ToListAsync() in Unit-test with moq?
我正在尝试使用 moq 在 ASP.NET Core MVC 应用程序中创建单元测试。不幸的是,Linq
在这段代码中,我模拟了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | var entities = new List<RequestRole> { new RequestRole() { Id = 0, RequestOperator = new RequestOperator() { Id = 1 } }, new RequestRole() { Id = 1, RequestOperator = new RequestOperator() { Id = 2 } } } .AsQueryable(); // for ToListAsync Mock INhQueryProvider and set it into IQueryable var queryableProviderMock = new Mock<INhQueryProvider>(); queryableProviderMock.Setup(x => x.ExecuteAsync<IEnumerable<RequestRole>>(It.IsAny<Expression>(), It.IsAny<CancellationToken>())) .ReturnsAsync(entities); var queryableMock = new Mock<IQueryable<RequestRole>>(); queryableMock.Setup(x => x.Provider).Returns(queryableProviderMock.Object); queryableMock.Setup(x => x.Expression).Returns(entities.Expression); queryableMock.Setup(x => x.GetEnumerator()).Returns(entities.GetEnumerator()); queryableMock.Setup(x => x.ElementType).Returns(entities.ElementType); // mock CreateQuery, without this Linq.Where throwing"System.NotSupportedException: 'Source Provider must be a INhQueryProvider'" queryableProviderMock.As<INhQueryProvider>() .Setup(x => x.CreateQuery<RequestRole>(It.IsAny<Expression>())) .Returns(queryableMock.Object); var session = new Mock<ISession>(); session.Setup(s => s.Query<RequestRole>()).Returns(queryableMock.Object); var returns = session.Object.Query<RequestRole>(); // check work var tolistasync = await returns .Where(x => x.Id != 0) .ToListAsync(); |
在这种情况下
似乎我应该正确地模拟
您需要指示 CreateQuery 使用该表达式。正如您所见,仅返回模拟的可查询对象不会做任何事情。此外,CreateQuery 将需要返回一个带有实现 INhQueryProvider 的提供程序的 IQueryable。问题在于 Provider 属性没有设置器,因此您无法在现有的可查询对象上设置它。
我解决类似问题的方法是创建自己的序列,我可以在其中设置提供程序。
从创建实现
的提供程序的查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | public class TestingQueryable< T > : IQueryable< T > { private readonly IQueryable< T > _queryable; public TestingQueryable(IQueryable< T > queryable) { _queryable = queryable; Provider = new TestingQueryProvider< T >(_queryable); } public Type ElementType => _queryable.ElementType; public Expression Expression => _queryable.Expression; public IQueryProvider Provider { get; } public IEnumerator< T > GetEnumerator() { return _queryable.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return _queryable.GetEnumerator(); } } public class TestingQueryProvider< T > : INhQueryProvider { public TestingQueryProvider(IQueryable< T > source) { Source = source; } public IQueryable< T > Source { get; set; } public IQueryable CreateQuery(Expression expression) { throw new NotImplementedException(); } public IQueryable<TElement> CreateQuery<TElement>(Expression expression) { return new TestingQueryable<TElement>(Source.Provider.CreateQuery<TElement>(expression)); } public object Execute(Expression expression) { throw new NotImplementedException(); } public TResult Execute<TResult>(Expression expression) { return Source.Provider.Execute<TResult>(expression); } public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken) { return Task.FromResult(Execute<TResult>(expression)); } public int ExecuteDml<T1>(QueryMode queryMode, Expression expression) { throw new NotImplementedException(); } public Task<int> ExecuteDmlAsync<T1>(QueryMode queryMode, Expression expression, CancellationToken cancellationToken) { throw new NotImplementedException(); } public IFutureEnumerable<TResult> ExecuteFuture<TResult>(Expression expression) { throw new NotImplementedException(); } public IFutureValue<TResult> ExecuteFutureValue<TResult>(Expression expression) { throw new NotImplementedException(); } public void SetResultTransformerAndAdditionalCriteria(IQuery query, NhLinqExpression nhExpression, IDictionary<string, Tuple<object, IType>> parameters) { throw new NotImplementedException(); } } |
更新您的查询提供程序设置以使用您的 IQueryable 实现:
1 2 3 4 5 6 | queryProviderMock .Setup(x => x.CreateQuery<RequestRole>(It.IsAny<Expression>())) .Returns((Expression providedExpression) => { return new TestingQueryable<RequestRole>(queryable.Provider.CreateQuery<RequestRole>(providedExpression)); }); |
运行
工作示例
您可以更进一步,只需设置 ISession 模拟以使用您的 IQueryable 实现,如果您不需要专门模拟它,请取消模拟查询提供程序。如果您知道我的意思,我通常不会模拟模拟返回的内容,因此这符合我的同行评审标准。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | [Test] public async Task Test2() { var requestRoles = new List<RequestRole>(); requestRoles.Add(new RequestRole { Id = 0, RequestOperator = new RequestOperator { Id = 1 } }); requestRoles.Add(new RequestRole { Id = 1, RequestOperator = new RequestOperator { Id = 2 } }); var sessionMock = new Mock<ISession>(); sessionMock.Setup(s => s.Query<RequestRole>()).Returns(new TestingQueryable<RequestRole>(requestRoles.AsQueryable())); var query = sessionMock.Object.Query<RequestRole>(); var result = await query.Where(x => x.Id != 0).ToListAsync(); Assert.Multiple(() => { Assert.That(result.Count, Is.EqualTo(1)); Assert.That(result.Single(), Is.EqualTo(requestRoles.Last())); }); } |