c# - 如何在单元测试中使用 Moq 和 DbFunctions 来防止 NotSupportedException?

标签 c# entity-framework unit-testing moq

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

我已将此范围缩小到我对 DbFunctions.TruncateTime 的使用,但我不知道有什么方法可以让单元测试反射(reflect)实时服务器上发生的情况。

这是我正在使用的方法:

    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);
    }

编辑 2:这是相关测试的消息和调试跟踪:

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服务器)。

最佳答案

我知道我来晚了,但一个非常简单的解决方法是编写您自己的使用 DbFunction 属性的方法。然后使用该函数代替 DbFunctions.TruncateTime。

[DbFunction("Edm", "TruncateTime")]
public static DateTime? TruncateTime(DateTime? dateValue)
{
    return dateValue?.Date;
}

使用此函数将在 Linq to Entities 使用时执行 EDM TruncateTime 方法,否则将运行提供的代码。

关于c# - 如何在单元测试中使用 Moq 和 DbFunctions 来防止 NotSupportedException?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32782128/

相关文章:

c# - 如何手动触发 Datagridview.cellValidating?

c# - C# Winforms 中的文本框验证 - 应仅允许 1-100 之间的数字

c# - 错误 175 : The ADO. 具有不变名称 'MySql.Data.MySqlClient' 的 NET 提供程序未在计算机或应用程序配置文件中注册

unit-testing - NHibernate/Npgsql 在调试 UnitTest 时在 CreateSchema 期间抛出异常

c# - 如何使用 NSubstitute 假调用当前类的方法?

c# - 获取 xelement 属性值

c# - 如何在循环中构建动态linq表达式树

entity-framework - 流畅的 API 可以在从基类继承的所有实体上设置 NotMapped 吗?

c# - 如何在我的程序中记录从 DbContext.SaveChanges() 生成的 SQL?

node.js - NodeJS 测试,默认异步,实时结果