Деревья выражений модульного тестирования - PullRequest
10 голосов
/ 04 мая 2009

Мне недавно нужно было построить дерево выражений, чтобы я написал метод Test примерно так ...

    /// <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))>.

Я просто не понимаю, почему ... У кого-нибудь есть общие советы по выражениям модульного тестирования и предложения, как пройти мой конкретный тест?

Спасибо ...

1 Ответ

15 голосов
/ 04 мая 2009

На основании кода, который вы разместили,

  • ожидаемое значение - анонимный делегат / метод. CLR делает немного магии за сценой, чтобы добавить метод на лету. В случае анона. Метод использует определенные локальные переменные, CLR создает новый класс с полями, для которых установлены эти значения, с новым методом anon внутри него (чтобы метод мог получить доступ к локальным значениям var). Так что это ваш ..c_DisplayClass13, с компилятором, которому присвоено странное имя, чтобы он не конфликтовал с пользовательскими методами.
  • Фактическое значение, возвращаемое вашим методом: Expression<T>.

И, следовательно ... проверка на равенство между этими двумя не удалась. Вам нужно сравнить элементы коллекции, возвращенные обоими. Поэтому я бы предложил .. преобразовать ожидаемые и фактические значения в списки (или лучшую структуру данных), а затем вызвать одно из утверждений NUnit, которые принимают параметры сбора.

Обновление : Вы заставили меня прочитать о Деревьях выражений. +1 за это.
Я собираюсь изменить свой ответ - Сравнение деревьев выражений с помощью метода взлома и утверждения может привести к хрупкому тесту (например, если MS изменит внутреннюю структуру дерева выражений в будущем)
Деревья выражений - это просто блоки кода (как я выяснил сейчас), которые оценивают результат, похожий на Func<TInput,TResult), поэтому мой тест состоял бы в том, чтобы дать ожидаемым и фактическим блокам кода одинаковый ввод и посмотреть, дают ли они одинаковый вывод. Таким образом, мое утверждение для вашего теста будет

Assert.AreEqual(expected.Compile().Invoke(inputEntity), 
                actual.Compile().Invoke(inputEntity));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...