Teste de Unidade Árvores de expressão
-
03-07-2019 - |
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 ...
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));