TDD: Verifying ExpandoObject Properties
Whilst working with a Facebook SDK on a recent project I came across the need to verify the Post
method on the FacebookClient
called with the correct parameters on a dynamic object.
The Facebook client uses reflection to get the required data from the parameters object but I don’t see a need to create a class with the properties when I can just use a dynamic object.
My final test is as follows:
[Fact]
public void PostMethodCalledWithParametersObjectContainingMessage()
{
//arrange
string message = "test message";
var sut = new FacebookPost(message, _mockFacebookClient.Object);
//act
sut.Post();
//assert
_mockFacebookClient.Verify(
x => x.Post(
It.IsAny<string>(),
It.Is<ExpandoObject>(o => And.HasProperty(o, "message"))
));
}
You can see that I’m verifying that the second parameter to Post
is an ExpandoObject and that I’m using a helper class to check it has a certain property. ExpandoObject
implements IDictionary<object,string>
therefore I can cast the parameters object in my helper and use the ContainsKey(string key)
method to check if the dynamic property exists on the object.
The code for my helper class is as follows:
public static class And
{
public static bool HasProperty(ExpandoObject filter, string name)
{
return ((IDictionary<string, object>)filter).ContainsKey(name);
}
}
Just for reference the code I’m testing is below:
public void Post()
{
dynamic parameters = new ExpandoObject();
parameters.message = Message;
_facebookClient.Post(Message,parameters);
}
You can see that I have named the helper class And
this is to make the tests read more fluently and be more descriptive. Your tests provide detailed descriptions of the behaviour of the code and therefore if you can make them more descriptive this can only be a good thing.
Following on from checking that an object with the message
property is passed I also want to check the value of that property. I have written another test to check its value.
[Fact]
public void ParametersObjectHasMessageSetCorrectly()
{
//arrange
var sut = new FacebookPost(message, _mockFacebookClient.Object);
//act
sut.Post();
//assert
_mockFacebookClient.Verify(
x => x.Post(
It.IsAny<string>(),
It.Is<ExpandoObject>(o => And.Property(o,"message").HasValue(message))
));
}
Again you’ll notice the almost plain English syntax. I’ve had to add a small Property
class to support this alongside the And
class however this helps make the tests more readable.
The And
class has a method called Property
which returns a property with the given name, this can then be used to check the value.
internal static class And
{
internal static bool HasProperty(ExpandoObject filter, string name)
{
return ((IDictionary<string, object>)filter).ContainsKey(name);
}
internal static Property Property(ExpandoObject expandoObject, string propertyName)
{
var dict = (IDictionary<string, object>) expandoObject;
return new Property(propertyName, dict[propertyName]);
}
}
The Property
object then has a method called HasValue
which I then call to check if the property returned has the value supplied to the method.
internal class Property
{
private readonly string _key;
private readonly object _value;
public Property(string key, object value)
{
_key = key;
_value = value;
}
public bool HasValue(object value)
{
return value == _value;
}
}
As the two classes And
and Property
are only used within these two tests I’ve let them within the same source code file as the tests. At this point there’s no benefit to moving them to their own files. Keeping them within the test source code makes more sense!