Moq和DbFunctions

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (119)

我目前正试图对通过实体框架运行的查询运行一些单元测试。查询本身在实时版本上运行时没有任何问题,但单元测试总是失败。

我已经缩小到了我对DbFunctions.TruncateTime的使用范围,但我不知道解决此问题的方法,以便使单元测试能够反映活动服务器上正在发生的事情。

以下是我正在使用的方法:

    public System.Data.DataTable GetLinkedUsers(int parentUserId)
    {
        var today = DateTime.Now.Date;

        var query = from up in DB.par_UserPlacement
                    where up.MentorId == mentorUserId
                        && DbFunctions.TruncateTime(today) >= DbFunctions.TruncateTime(up.StartDate)
                        && DbFunctions.TruncateTime(today) <= DbFunctions.TruncateTime(up.EndDate)
                    select new
                    {
                        up.UserPlacementId,
                        up.Users.UserId,
                        up.Users.FirstName,
                        up.Users.LastName,
                        up.Placements.PlacementId,
                        up.Placements.PlacementName,
                        up.StartDate,
                        up.EndDate,
                    };

        query = query.OrderBy(up => up.EndDate);

        return this.RunQueryToDataTable(query);
    }

如果我在DbFunctions中注释掉这些行,测试全部通过(除了那些正在检查给定日期的有效结果运行的测试外)。

有没有我可以提供DbFunctions.TruncateTime的模拟版本在这些测试中使用?本质上它应该只是返回Datetime.Date,但在EF查询中不可用。

这是使用日期检查失败的测试:

    [TestMethod]
    public void CanOnlyGetCurrentLinkedUsers()
    {
        var up = new List<par_UserPlacement>
        {
            this.UserPlacementFactory(1, 2, 1), // Create a user placement that is current
            this.UserPlacementFactory(1, 3, 2, false) // Create a user placement that is not current
        }.AsQueryable();

        var set = DLTestHelper.GetMockSet<par_UserPlacement>(up);

        var context = DLTestHelper.Context;
        context.Setup(c => c.par_UserPlacement).Returns(set.Object);

        var getter = DLTestHelper.New<LinqUserGetLinkedUsersForParentUser>(context.Object);

        var output = getter.GetLinkedUsers(1);

        var users = new List<User>();
        output.ProcessDataTable((DataRow row) => students.Add(new UserStudent(row)));

        Assert.AreEqual(1, users.Count);
        Assert.AreEqual(2, users[0].UserId);
    }

这是来自相关测试的消息和调试跟踪:

Test Result: Failed

Message: Assert.AreEqual failed. Expected:<1>. Actual:<0>

Debug Trace: This function can only be invoked from LINQ to Entities

从我读到的,这是因为没有一个LINQ to Entities实现这个方法,可以在这个地方用于单元测试,虽然有实时版本(因为它正在查询一个SQL服务器)。

提问于
用户回答回答于
[TestMethod]
public void CanOnlyGetCurrentLinkedUsers()
{
    using (ShimsContext.Create())
    {
        System.Data.Entity.Fakes.ShimDbFunctions.TruncateTimeNullableOfDateTime =
            (DateTime? input) =>
            {
                return input.HasValue ? (DateTime?)input.Value.Date : null;
            };

        var up = new List<par_UserPlacement>
        {
            this.UserPlacementFactory(1, 2, 1), // Create a user placement that is current
            this.UserPlacementFactory(1, 3, 2, false) // Create a user placement that is not current
        }.AsQueryable();

        var set = DLTestHelper.GetMockSet<par_UserPlacement>(up);

        var context = DLTestHelper.Context;
        context.Setup(c => c.par_UserPlacement).Returns(set.Object);

        var getter = DLTestHelper.New<LinqUserGetLinkedUsersForParentUser>(context.Object);

        var output = getter.GetLinkedUsers(1);
    }

    var users = new List<User>();
    output.ProcessDataTable((DataRow row) => users.Add(new User(row)));

    Assert.AreEqual(1, users.Count);
    Assert.AreEqual(2, users[0].UserId);
}
用户回答回答于

测试查询的另一种方法是在另一个项目上实现的:使用VS out of box单元测试,每个查询(再次重构为其自己的方法)测试将被包装在事务范围中。然后项目的测试框架将负责手动将假数据输入到数据库中,并且查询将尝试过滤这些假数据。最后,交易永远不会完成,因此回滚。 由于交易范围的性质,这可能不是很多项目的理想场景。 最有可能不在产品环境中。

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励