System.TypeLoadException.IAsyncQueryProvider 无法加载类型'Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryProvider'。

问题描述 投票:0回答:1

我正在我的.NET Core Web应用程序中使用测试我的个人信息动作,但一直遇到问题。我最近找到了一种方法来创建一个模拟的usermanager,而不会在它的参数上遇到问题,但随后我又遇到了一个新的错误,我也找不到任何解决方案。"System.TypeLoadException: 无法加载类型'Microsoft.EntityFrameworkCore.Query.Internal.IAsyncQueryProvider'"

这是我的相关代码。

设置模拟usermanager:

var _userManager = new Mock<FakeUserManager>();
            UserIdentity user1 = new UserIdentity() { Id = UserId1, UserName = "[email protected]", Score = 5 };
            UserIdentity user2 = new UserIdentity() { Id = UserId2, UserName = "[email protected]", Score = 1 };
            UserIdentity user3 = new UserIdentity() { Id = UserId3, UserName = "[email protected]", Score = 0 };
            UserIdentity user4 = new UserIdentity() { Id = UserId4, UserName = "[email protected]", Score = 4 };
            List<UserIdentity> users = new List<UserIdentity>() { user1, user2, user3, user4 };
            var mock = users.AsQueryable().BuildMock();
            _userManager.Setup(x => x.Users).Returns(mock.Object);

var identityRepository = new IdentityRepository(_userManager.Object, null, null);
            _identityService = new IdentityService(identityRepository);

FakeUserManager.cs:

public class FakeUserManager : UserManager<UserIdentity>
    {
        public FakeUserManager()
            : base(new Mock<IUserStore<UserIdentity>>().Object,
                  new Mock<IOptions<IdentityOptions>>().Object,
                  new Mock<IPasswordHasher<UserIdentity>>().Object,
                  new IUserValidator<UserIdentity>[0],
                  new IPasswordValidator<UserIdentity>[0],
                  new Mock<ILookupNormalizer>().Object,
                  new Mock<IdentityErrorDescriber>().Object,
                  new Mock<IServiceProvider>().Object,
                  new Mock<ILogger<UserManager<UserIdentity>>>().Object)
        { }

    }

测试方法:

        [TestMethod()]
        public async Task GetUserAsyncTest()
        {
            //Arrange

            //Act
            var user = await _identityService.GetUserAsync(UserId4);

            //Assert
            Assert.AreEqual("[email protected]", user.UserName);
        }

有谁知道解决我的问题的旁路方法吗?

更新:堆栈跟踪。

EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, Expression expression, CancellationToken cancellationToken)
    EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, CancellationToken cancellationToken)
    EntityFrameworkQueryableExtensions.SingleOrDefaultAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
    IdentityRepository.GetUserAsync(Nullable`1 userId) line 55
    IdentityService.GetUserAsync(Nullable`1 id) line 172
    IdentityServiceTests.GetUserAsyncTest() line 102
    ThreadOperations.ExecuteWithAbortSafety(Action action)

以及版本库中的GetUserAsync方法。

        public async Task<UserIdentity> GetUserAsync(Guid? userId)
        {
            return await _userManager.Users.Where(x => x.Id.Equals(userId)).SingleOrDefaultAsync();
        }
unit-testing asp.net-core entity-framework-core asp.net-identity moq
1个回答
0
投票

仓库中的 _users 序列需要一个能实现 IAsyncQueryProvider. 有几种方法可以做到,下面是一个模拟的实现。

首先,根据你的OP做一些脚手架。

public class UserIdentity : IdentityUser<Guid>
{
    public int Score { get; set; }
}

public class IdentityRepository
{
    readonly UserManager<UserIdentity> _userManager;

    public IdentityRepository(UserManager<UserIdentity> userManager)
    {
        _userManager = userManager;
    }

    public async Task<UserIdentity> GetUserAsync(Guid? userId)
    {
        return await _userManager.Users.SingleOrDefaultAsync(x => x.Id.Equals(userId));
    }
}

创建你的模拟 IAsyncQueryProvider 并将其添加到自己的 IQueryable<UserIdentity>:

var user1 = new UserIdentity() { Id = Guid.NewGuid(), UserName = "[email protected]", Score = 1 };
var user2 = new UserIdentity() { Id = Guid.NewGuid(), UserName = "[email protected]", Score = 2 };
var user3 = new UserIdentity() { Id = Guid.NewGuid(), UserName = "tony stark", Score = 3000 };
var dataSource = new List<UserIdentity> { user1, user2, user3 }.AsQueryable();

var providerMock = new Mock<IAsyncQueryProvider>();
providerMock.Setup(x => x.ExecuteAsync<Task<UserIdentity>>(It.IsAny<Expression>(), It.IsAny<CancellationToken>()))
    .Returns((Expression providedExpression, CancellationToken providedCancellationToken) => Task.FromResult(dataSource.Provider.Execute<UserIdentity>(providedExpression)));

var usersMock = new Mock<IQueryable<UserIdentity>>();
usersMock.Setup(x => x.ElementType).Returns(dataSource.ElementType);
usersMock.Setup(x => x.Expression).Returns(dataSource.Expression);
usersMock.Setup(x => x.Provider).Returns(providerMock.Object);

...

userManagerMock.Setup(x => x.Users).Returns(() => usersMock.Object);

你需要一个方法来设置 IQueryable<T> 提供者,以上只是你可以做到的一种方式。

如果我们把这些都拉到一个工作的LINQPad示例中。

void Main()
{
    var user1 = new UserIdentity() { Id = Guid.NewGuid(), UserName = "[email protected]", Score = 1 };
    var user2 = new UserIdentity() { Id = Guid.NewGuid(), UserName = "[email protected]", Score = 2 };
    var user3 = new UserIdentity() { Id = Guid.NewGuid(), UserName = "tony stark", Score = 3000 };
    var dataSource = new List<UserIdentity> { user1, user2, user3 }.AsQueryable();

    var providerMock = new Mock<IAsyncQueryProvider>();
    providerMock.Setup(x => x.ExecuteAsync<Task<UserIdentity>>(It.IsAny<Expression>(), It.IsAny<CancellationToken>()))
        .Returns((Expression providedExpression, CancellationToken providedCancellationToken) => Task.FromResult(dataSource.Provider.Execute<UserIdentity>(providedExpression)));

    var usersMock = new Mock<IQueryable<UserIdentity>>();
    usersMock.Setup(x => x.ElementType).Returns(dataSource.ElementType);
    usersMock.Setup(x => x.Expression).Returns(dataSource.Expression);
    usersMock.Setup(x => x.Provider).Returns(providerMock.Object);

    var userManagerMock = new Mock<UserManager<UserIdentity>>
            (new Mock<IUserStore<UserIdentity>>().Object,
                  new Mock<IOptions<IdentityOptions>>().Object,
                  new Mock<IPasswordHasher<UserIdentity>>().Object,
                  new IUserValidator<UserIdentity>[0],
                  new IPasswordValidator<UserIdentity>[0],
                  new Mock<ILookupNormalizer>().Object,
                  new Mock<IdentityErrorDescriber>().Object,
                  new Mock<IServiceProvider>().Object,
                  new Mock<ILogger<UserManager<UserIdentity>>>().Object);

    userManagerMock.Setup(x => x.Users).Returns(() => usersMock.Object);

    var identityRepository = new IdentityRepository(userManagerMock.Object);

    var result = identityRepository.GetUserAsync(user2.Id).Result;

    Console.WriteLine(result);
}

public class UserIdentity : IdentityUser<Guid>
{
    public int Score { get; set; }
}

public class IdentityRepository
{
    readonly UserManager<UserIdentity> _userManager;

    public IdentityRepository(UserManager<UserIdentity> userManager)
    {
        _userManager = userManager;
    }

    public async Task<UserIdentity> GetUserAsync(Guid? userId)
    {
        return await _userManager.Users.SingleOrDefaultAsync(x => x.Id.Equals(userId));
    }
}

我们就会得到想要的结果。

enter image description here

我省略了你的 IdentityService 在上面,因为本质上这是一个细节的答案;你只需要得到一个工作的,模拟的。UserManager. 对于我的模拟图书馆,特别是 EntityFrameworkCore.Testing我想用混凝土 IAsyncQueryProvider 而不是模拟;如果你想走这条路,请按照链接看一个例子。

© www.soinside.com 2019 - 2024. All rights reserved.