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!