I recently need to build a Expression tree so I wrote a Test method like so...
/// <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());
}
When I finally got the "BuildForeignKeysContainsPredicate" method working I could never get teh test to pass... Here is the method:
/// <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;
}
But the test fails every time, I switched the line Assert.AreEqual(expected, actual);
to this: Assert.AreEqual(expected.ToString(), actual.ToString());
I understand why it is failing because when you look at the results of the ToString method they are different.
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))>.
I just don't understand why... Does any one have general tips on unit testing expressions and suggestions how to get my specific test to pass?
Thanks...
Based on the code you've posted,
Expression<T>
.And hence.. the equality check between these two fails. You need to compare the elements of the collection returned by both of them. So I'd suggest.. convert both the expected and actual values to Lists (or a better data structure) and then invoke one of NUnit's asserts that take collection parameters.
Update: You got me to read up on Expression Trees. +1 for that.
I'm going to change my answer - Comparing the Expression trees via hack-and-assert would lead to a fragile test (e.g. if MS changes the internal structure of an expression tree in the future)
Expression trees are just code blocks (as I found out now) that evaluate to a result similar to a Func<TInput,TResult)
- so my test would be to give the expected and actual code blocks the same input and see if they deliver the same output.
So my assert for your test would be
Assert.AreEqual(expected.Compile().Invoke(inputEntity),
actual.Compile().Invoke(inputEntity));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With