Unit Testing Expression Tree Equality
Sometimes you need to test whether two expressions are the same. However when you do a simple AreEqual() test on two expressions that look the same you get a negative result.
This method will fail
[TestMethod]
public void TestDoesNotWork()
{
Expression<Func<int, int>> expressionA = x => x + 1;
Expression<Func<int, int>> expressionB = x => x + 1;
Assert.AreEqual(expressionA, expressionB);
}
This looks like it should work however it doesn’t. This is because when using anonymous expressions/delegates the CLR does some magic behind the scene to add a method on the fly, creating a new instance for every anonymous expression/delegate.
So if you have two expressions that are syntactically the same but not the same reference the easiest way to ensure they are the same is to compile the expression and invoke it comparing the resultant value.
[TestMethod]
public void TestDoesWork()
{
Expression<Func<int, int>> expressionA = x => x + 1;
Expression<Func<int, int>> expressionB = x => x + 1;
Assert.AreEqual(expressionA.Compile().Invoke(3), expressionB.Compile().Invoke(3));
}
An alternate approach would be to de-construct each constituent part of the expression trees comparing each part as you go. This however is far more complex.
For a more real world example that involves using Rhino mocks and Expect calls please read on:
When using Rhino Mocks and setting up an Expect call on a method that takes an expression you will most likely find that the Expect assertion always fails.
The class that will be mocked out.
This class will have the method on it that takes an expression.
public class Repository
{
public virtual void Get<TEntity>(Expression<Func<TEntity, bool>> whereCondition)
{
// Actual logic.
}
}
The class we are unit testing
public class UserManager
{
public Repository Repo { get; set; }
public void GetUserById(int id)
{
Repo.Get<User>(x => x.Id == id);
}
}
Supporting classes
public class User
{
public int Id { get; set; }
public int Name { get; set; }
}
For our unit test we want to test that when we call the GetUserById() method on the UserManager class that we Expect the Repository.Get
Unit Test
[TestMethod]
public void Test()
{
// Arrange
UserManager manager = new UserManager { Repo = MockRepository.GenerateMock<Repository>() };
manager.Repo.Expect(r => r.Get<User>(x => x.Id == 3));
// Act
manager.GetUserById(3);
// Assert
manager.Repo.VerifyAllExpectations();
}
This looks like it should work however it won’t.
So using the approach listed earlier we can test that the method with an expression is called with the correct value by compiling and invoking the expected expression and the actual expression that was called and comparing their values.
[TestMethod]
public void TestExpressionCalled()
{
// Arrange
UserManager manager = new UserManager { Repo = MockRepository.GenerateMock<Repository>() };
// Act
manager.GetUserById(3);
// Assert
Expression<Func<User, bool>> expected = x => x.Id == 3;
Expression<Func<User, bool>> actual = (Expression<Func<User, bool>>)manager.Repo.GetArgumentsForCallsMadeOn(r => r.Get<User>(null))[0][0];
User user = new User { Id = 3 };
Assert.AreEqual(expected.Compile().Invoke(user), actual.Compile().Invoke(user));
}
Tags: Comparison, Equality, Expression Trees, Mocks, Rhino
Correct me if im wrong. (anyone please) but this will only actually test that the final output value of the Actual Expression is the same as the final output value of the Expected Expression, given some dummy input value. It wont actually test expression equality since some simple logic would show that you can have two completely different expressions return the same result for any given input.
You’re a douche ;)
The snippet:
“So if you have two expressions that are syntactically the same but not the same reference the easiest way to ensure they are the same is to compile the expression and invoke it comparing the resultant value.”
Says exactly that.
*jerk*
Hi,
It seems like compiling the expression and invoking it with an arbitrary value is a really bad way of unit testing expressions, because the only way to be certain that the expressions are for all intents and purposes equal is to perform this comparison with every possible value. That’s not too big a task when the input is a single Int32, but considering System.Func can accept up to 5 input parameters even testing with ints will get unrealistic very quickly.
It seems like the best way to test equivalence of expressions is to do as you suggest and compare each part of the tree using an expression visitor. This isn’t very hard to do. In fact, I’ve written an expression visitor that does exactly this in less than 200 lines of code, and most of those lines are very mundane. You’re welcome to it if you’d like.
Thanks,
Ian
Ian,
That sounds like a great idea. We could feature it in an upcoming post if you like?