Pergunta

Recentemente precisa para construir uma árvore de expressão então eu escrevi um método de teste assim ...

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

Quando finalmente consegui o método "BuildForeignKeysContainsPredicate" trabalho eu nunca poderia se teh teste para passar ... Aqui está o método:

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

Mas o teste falhar cada vez, eu mudei o Assert.AreEqual(expected, actual); linha a isto:. Assert.AreEqual(expected.ToString(), actual.ToString()); eu entendo porque ele está falhando, porque quando você olha para os resultados do método ToString eles são diferentes

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

Eu só não entendo por que ... Será que qualquer um tem dicas gerais sobre unidade testar expressões e sugestões Como obter o meu teste específico para passar?

Obrigado ...

Foi útil?

Solução

Com base no código que você postou,

  • o valor esperado é um delegado / método anônimo. O CLR faz alguma magia por trás da cena para adicionar um método em tempo real. No caso do Anon. método usa certas variáveis ??locais, o CLR cria uma nova classe com campos definidos para estes valores, com o novo método Anon dentro dele (para que o método pode acessar os valores var locais). Então essa é a sua ..c_DisplayClass13, com um compilador determinado nome estranho para que ele não colidir com os métodos definidos pelo usuário.
  • O valor real retornado por seu método é uma Expression<T>.

E, portanto, .. a verificação de igualdade entre estes dois falhar. Você precisa comparar os elementos da coleção retornada por ambos. Então eu sugiro .. convertido ambos os valores previstos e reais a listas (ou uma melhor estrutura de dados) e, em seguida, invocar um dos NUnit do afirma que os parâmetros de recolha de take.

Atualizar : Você me pegou para ler sobre Árvores de expressão. +1 para isso.
Eu vou mudar a minha resposta - Comparando as árvores de expressão através de hack-and-assert levaria a um teste frágil (por exemplo, se o MS muda a estrutura interna de uma árvore de expressão no futuro)
Árvores de expressão são apenas blocos de código (como eu descobri agora) que avaliam a um resultado semelhante a um Func<TInput,TResult) - assim meu teste seria dar os blocos de código previstos e reais a mesma entrada e ver se eles oferecem a mesma saída. Assim, a minha assert para o teste seria

Assert.AreEqual(expected.Compile().Invoke(inputEntity), 
                actual.Compile().Invoke(inputEntity));
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top