【问题标题】:Unit Testing Expression Trees单元测试表达式树
【发布时间】:2009-05-04 18:09:06
【问题描述】:

我最近需要构建一个表达式树,所以我写了一个这样的测试方法......

    /// <summary>
    /// 
    /// </summary>
    [TestMethod()]
    [DeploymentItem("WATrust.Shared.Infrastructure.dll")]
    public void BuildForeignKeysContainsPredicate_shoud_build_contains_predicate()
    {
        RemoteEntityRefLoader_Accessor<ReferencedEntity> target = CreateRemoteEntityRefLoader_Accessor();

        List<object> foreignKeys = new List<object>() { 1, 2, 3, 4 };
        Expression<Func<ReferencedEntity, bool>> expected = (ReferencedEntity referencedEntity) => foreignKeys.Contains(referencedEntity.Id);
        Expression<Func<ReferencedEntity, bool>> actual;

        actual = target.BuildForeignKeysContainsPredicate(foreignKeys, "Id");

        Assert.AreEqual(expected.ToString(), actual.ToString());
    }

当我终于让“BuildForeignKeysContainsPredicate”方法工作时,我永远无法通过测试...这是方法:

    /// <summary>
    /// 
    /// </summary>
    /// <param name="foreignKeys"></param>
    /// <returns></returns>
    private Expression<Func<TReferencedEntity, bool>> BuildForeignKeysContainsPredicate(List<object> foreignKeys, string primaryKey)
    {
        Expression<Func<TReferencedEntity, bool>> result = default(Expression<Func<TReferencedEntity, bool>>);

        try
        {
            ParameterExpression entityParameter = Expression.Parameter(typeof(TReferencedEntity), "referencedEntity");
            ConstantExpression foreignKeysParameter = Expression.Constant(foreignKeys, typeof(List<object>));
            MemberExpression memberExpression = Expression.Property(entityParameter, primaryKey);
            Expression convertExpression = Expression.Convert(memberExpression, typeof(object));
            MethodCallExpression containsExpression = Expression.Call(foreignKeysParameter
                , "Contains", new Type[] { }, convertExpression);

            result = Expression.Lambda<Func<TReferencedEntity, bool>>(containsExpression, entityParameter);

        }
        catch (Exception ex)
        {
            throw ex;
        }

        return result;
    }

但是每次都测试失败,我换了线Assert.AreEqual(expected, actual); 对此:Assert.AreEqual(expected.ToString(), actual.ToString()); 我理解它为什么会失败,因为当您查看 ToString 方法的结果时,它们是不同的。

Assert.AreEqual failed.
Expected:<referencedEntity => value(Shared.Infrastructure.Test.RemoteEntityRefLoaderTest+<>c__DisplayClass13).foreignKeys.Contains(Convert(referencedEntity.Id))>.
Actual  :<referencedEntity => value(System.Collections.Generic.List`1[System.Object]                        )            .Contains(Convert(referencedEntity.Id))>.

我只是不明白为什么...有没有人对单元测试表达式有一般提示和建议如何让我的特定测试通过?

谢谢...

【问题讨论】:

    标签: c# linq unit-testing testing lambda


    【解决方案1】:

    根据您发布的代码,

    • 预期值为匿名委托/方法。 CLR 在幕后做了一些魔术来动态添加一个方法。以防万一。方法使用某些局部变量,CLR 创建一个新类,其字段设置为这些值,其中包含新的 anon 方法(以便该方法可以访问局部 var 值)。这就是你的 ..c_DisplayClass13,编译器的名字很奇怪,这样它就不会与用户定义的方法发生冲突。
    • 您的方法返回的实际值为Expression&lt;T&gt;

    因此.. 这两者之间的相等性检查失败。您需要比较它们返回的集合的元素。所以我建议.. 将预期值和实际值都转换为列表(或更好的数据结构),然后调用 NUnit 的一个采用集合参数的断言。

    更新:你让我阅读了表达式树。为此 +1。
    我要改变我的答案 - 通过 hack-and-assert 比较表达式树会导致脆弱的测试(例如,如果 MS 将来更改表达式树的内部结构)
    表达式树只是代码块(正如我现在发现的那样),其评估结果类似于Func&lt;TInput,TResult) - 所以我的测试是为预期和实际代码块提供相同的输入,并查看它们是否提供相同的输出。 所以我对你的测试的断言是

    Assert.AreEqual(expected.Compile().Invoke(inputEntity), 
                    actual.Compile().Invoke(inputEntity));
    

    【讨论】:

    • 你是说比较每个表达式中的每个节点吗?
    • 我喜欢它...我同意如果我开始比较表达式的各个部分并且 Microsoft 进行了一些更改,我可能会突然遇到很多失败的测试。我喜欢你的策略。谢谢!
    猜你喜欢
    • 2019-01-06
    • 1970-01-01
    • 1970-01-01
    • 2018-09-19
    • 2018-04-26
    • 2021-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多