Moq枚举在FirstOrDefault上消失

时间:2016-03-02 23:41:59

标签: c# unit-testing asp.net-membership moq

我已经编写了一个测试,用于验证一小部分新功能,该功能调用大型中间件功能,其中包含大量逻辑,将一种类型的用户(ASP网络成员用户)转换为内部用户(SystemUser) 。这是一个混乱的系统,但我不能把它撕掉,因此是新的测试。

我的测试调用了一个GetAllActiveUsers()方法,该方法调用了几个层并最终进入导致问题的枚举。该测试有一个模拟的实体框架datacontext Mock<localEntities> mockDb,其设置如下:

[SetUp]
public void Setup()
    {
        var mockUserSet = new Mock<DbSet<User>>();

        this.mockDb = new Mock<localEntities>();
        this.mockMembershipService = new Mock<IMembershipService>();
        this.mockRoleService = new Mock<IRoleService>();
        this.mockUserAgreementRelation = new Mock<DbSet<UserAgreementRelation>>();

        this.testUsers = this.CreateSystemUsers();

        this.mockDb.Setup(m => m.User).Returns(mockUserSet.Object);

        mockUserAgreementRelation.SetupAllProperties();

        var agreementRelations = this.testUsers.Select(u => new UserAgreementRelation() { AgentUserID = u.UserId, IsDeleted = null });

        mockUserAgreementRelation.As<IQueryable<UserAgreementRelation>>().Setup(ua => ua.GetEnumerator()).Returns(agreementRelations.GetEnumerator());
        this.mockDb.Setup(m => m.UserAgreementRelation).Returns(mockUserAgreementRelation.Object);
    }

在我的测试中,我设置了一些用户并调用var testActiveUsers = testRepo.GetAllActiveUsers();来调用问题行。

这是我感到困惑的地方。

测试通过以下代码:

var agreementRelations = databaseContext.UserAgreementRelation().ToList();

var userAgreementFromDB = agreementRelations
            .FirstOrDefault(x => x.AgentUserID == ramsUser.UserId && (x.IsDeleted == null || !(bool)x.IsDeleted));

但是使用此代码失败:

var userAgreementFromDB = databaseContext.UserAgreementRelation
            .FirstOrDefault(x => x.AgentUserID == ramsUser.UserId && (x.IsDeleted == null || !(bool)x.IsDeleted));

此外,如果我调试并逐步执行代码,我可以在模拟的UserAgreementRelation 上使用快速监视。我第一次看到我正在测试的每个用户的UserAgreementRelation。如果我再次运行手表,即使代码没有提前,枚举也不会产生任何结果。我猜这与这个问题有关。但是,由于我不知道为什么正在发生,我不知道它是如何导致这个问题的。

请记住,更简单的代码(没有ToList())是生产代码。它目前运行正常,但我的测试失败了。由于这是一个直接的数据库调用,枚举整个UserAgreementRelation表不是一个可行的解决方案。

建议?

2 个答案:

答案 0 :(得分:2)

我不确定我是否遇到了这个问题,因为你没有详细说明它是如何失败的&#34;。但也许你应该更改部分:

.Setup(ua => ua.GetEnumerator()).Returns(agreementRelations.GetEnumerator())

成:

.Setup(ua => ua.GetEnumerator()).Returns(() => agreementRelations.GetEnumerator())

原因是,如果您测试的代码多次调用GetEnumerator() ,则Moq不应该分发旧的&#34;使用过的&#34 ;枚举器实例可能已经提前到最后并可能被处置。相反,Moq应该重新运行Func<>,我的箭头() => agreementRelations.GetEnumerator(),以获取尚未提升(MoveNext())或关闭(Dispose())的新枚举器。< / p>

提问者通知我(在下面的评论中)他还需要Setup IQueryable {{1}} ProviderExpression

答案 1 :(得分:0)

我一直用这样的东西,试试这个。

var userAgreementFromDB = databaseContext.UserAgreementRelation
            .Where(x => x.AgentUserID == ramsUser.UserId && (x.IsDeleted == null || !(bool)x.IsDeleted)).FirstOrDefault();