Using Moles to isolate Deserialization of HttpResponse of Twitter API.


Moles (download link) is introduced by the Microsoft Research Team to help isolate .NET code. With moles you can replace any method from external resources to help you focus on the specific piece of code you want to test. In this blog I will show its usefulness of this add-in with a piece of code that uses the HttpClient and its extensions provided by the WCF starter kit (reference video). In this blog i use some simple code that calls on the Twitter API to get the messages from a specific twitter profile. In the code, there is a class called TwitterConnector with a public method called StatusTimeLine().

public class TwitterConnector
{
 /// <summary>
 /// Retrieves a timeline for the authenticated user or id. 
/// </summary>
public TwitterMessageCollection StatusTimeLine()
{
    HttpClient client = new HttpClient(“http://twitter.com/statuses/&#8221;);
    client.TransportSettings.Credentials = new NetworkCredential(“usr”, “pwd”);
    ServicePointManager.Expect100Continue = false;

    HttpResponseMessage response = client.Get(“home_timeline.xml”);
    response.EnsureStatusIsSuccessful();

    return response.Content.ReadAsDataContract<TwitterMessageCollection>();
}

The TwitterMessageCollection is defined as follows

[CollectionDataContract(Name = “statuses”, ItemName = “status”)]
public class TwitterMessageCollection : ICollection<TwitterMessage>{}

And TwitterMessage is defined as
[DataContract(Name = “status”)]

public class TwitterMessage
{
[DataMember(Name = “id”)]
    public string Id { get; set; }

    [DataMember(Name = “text”)]
    public string Text { get; set; }

    [DataMember(Name = “screen_name”)]
    public string Name { get; set; }

    [DataMember(Name = “user”)]
    public TwitterProfile User { get; set; }
}

The specific feature i would like to test is ReadAsDataContract which will validate our DataContract definition in TwitterMessageCollection and TwitterMessage. The Twitter API counts the number of calls made to the REST API for a specific account and limits it. When doing development you don’t want to be limited in your number of calls. For this particular case we can mole the call and response. Hence, we pretend getting a response using Moles and Pex. Before we can start working with Moles we need to create a .moles file which is created from any dll. This file will provide our test with fake (mole) objects. For a explanation on how to create the .moles files you need to review the Moles documentation.

To start creating the test which will fake our call we right-click inside our original method and choose Pex -> Create Parameterized Unit Test from the context menu. Follow the instructions on the screen and the add-in will add a new project to your solution containing the Unit Test.

If you open the new test class in the new project you’ll find a method that will look similar to:
/// <summary>Test stub for StatusTimeLine()</summary>
[PexMethod]
public TwitterMessageCollection StatusTimeLine([PexAssumeUnderTest]TwitterConnector target)
{
     TwitterMessageCollection result = target.StatusTimeLine();
     return result;
}

The first thing we need to do is to trap the HttpClient to make sure Pex will notify us when we call on any method or property from the HttpClient that is not moled.

/// <summary>Test stub for StatusTimeLine()</summary>
[PexMethod]
public TwitterMessageCollection StatusTimeLine([PexAssumeUnderTest]TwitterConnector target)
{
      //trap the client
      MHttpClient.BehaveAsNotImplemented();

     //invoke our method as we would in a regular case.
     TwitterMessageCollection result = target.StatusTimeLine();

     //return the result.
      return result;
}

If we run the Pex Exploration of this test by right-clicking inside the test and choose Run Pex Explorations. Pex will give us the first object that is trapped as MoleNotImplemented. In our case this will be:

MoleNotImplementedException, HttpClient.HttpClient(String) was not moled.

This exception is a good thing because Pex is telling us that the HttpClient we wanted to fake was not moled. We can mole the HttpClient by adding the following code

 /// <summary>Test stub for StatusTimeLine()</summary>
[PexMethod]
public TwitterMessageCollection StatusTimeLine([PexAssumeUnderTest]TwitterConnector target)
{
      //trap the client
      MHttpClient.BehaveAsNotImplemented();

     //mole constructing the httpclient
      MHttpClient.ConstructorString = (client, url) =>
      {
            //instance of the new client
            new MHttpClient(client){};
      };

     //invoke our method as we would in a regular case.
     TwitterMessageCollection result = target.StatusTimeLine();

     //return the result.
      return result;
}

ok, now we have moled the client and we can ask Pex to explore the test again and try to run our Test again. The exploration will give us another exception.

MoleNotImplementedException, HttpClient.get_TransportSettings() was not moled.

If we look at our original code this makes sense:
HttpClient client = new HttpClient(“http://twitter.com/statuses/&#8221;);
client.TransportSettings.Credentials = new NetworkCredential(“usr”, “pwd”);

after constructing our client we call on a property to set the TransportSettings and its credentials. Because of our trap, we need to mole this property too. We can do this by adding the following code to the test. The code actually moles the get property of the TransportSettings and the set property of the credentials of these TransportSettings.

MHttpClient.ConstructorString = (client, url) =>
{
     //instance of the new client
     new MHttpClient(client)
     {
            //mole the transportsettings
            TransportSettingsGet = () => new MHttpWebRequestTransportSettings()
            {
            CredentialsSetICredentials = (credential) => new System.Net.Moles.MNetworkCredential(credential.GetCredential(new Uri(_url), “Basic”))
            }
     };
}

We are almost there but not quite yet. If we run the exploration again we will encounter yet another exception.

failing test: MoleNotImplementedException, HttpClient.Send(HttpMethod, Uri) was not moled.

This is the method we were after. This is the actual call to the API we needed to intercept. We can mole this specific call by adding our last piece of code to the puzzle.

//Subsitute Call and Response
new MHttpClient(client)
{
                    //mole the transportsettings
                    TransportSettingsGet = () => new MHttpWebRequestTransportSettings()
                    {
                        CredentialsSetICredentials = (credential) => new System.Net.Moles.MNetworkCredential(credential.GetCredential(new Uri(_url), “Basic”))
                    },
                    //mole the send method (invoked by .Get())
                    SendHttpMethodUri = (method, uri) =>
                    {
                        //mole the response
                        return new MHttpResponseMessage()
                        {
                            //set the statuscode to OK
                            StatusCodeGet = () => { return System.Net.HttpStatusCode.OK; },

                            //mole dispose
                            Dispose = () => { },

                            //fake return
                            ContentGet = () => { return HttpContent.Create(_xml); }
                        };
                    }
                };
}

By adding the mole for the Send method we can intercept the invocation and send our own response to the serializer. I copied the xml from the Twitter API documentation into a resource file. the contents of the xml is returned as the response by ContentGet = () => {return HttpContent.Create(_xml);} because of our code before calling

//invoke our method as we would in a regular case.
TwitterMessageCollection result = target.StatusTimeLine();

The Twitter API is not used but the  response provided by the mole is used in

return response.Content.ReadAsDataContract<TwitterMessageCollection>();

One final problem we need to overcome is the maximum number of branches Pex can explore. We can set the maximum by adding a attribute to the PexMethod.

/// <summary>Test stub for StatusTimeLine()</summary>
[PexMethod(MaxBranches = 40000)]
public TwitterMessageCollection StatusTimeLine([PexAssumeUnderTest]TwitterConnector target)
….

Personally I like to create my own assertions in another TestMethod based in the same class. My simple Test looks like this:
[TestMethod]
[HostType(“Moles”)]
public void CanDeserializeIntoMessageCollection()
{
            //invoke our pex/moles method
            TwitterMessageCollection result = StatusTimeLine(new TwitterConnector());

            Assert.IsNotNull((object)result, “Deserialization Failed”);
            Assert.AreEqual<int>(2, result.Count, String.Format(“Expected 2 users but Found {0}”, result.Count));

            foreach (TwitterMessage msg in result)
            {
                     Console.WriteLine(“{0}”, msg.Id);
            }
        }

Important is the HostType attribute. This tells the framework to look for moles. Without this attribute your TestMethod will not run.

About these ads

3 thoughts on “Using Moles to isolate Deserialization of HttpResponse of Twitter API.

  1. Remi says:

    Very interesting read!

  2. shubham says:

    thnx . Do u have any document for Android integration with Twiter.

    pls suggest us.

    • dgcaron says:

      Sorry i didn’t reply, i missed the comment in the control panel. but the Twitter docs are pretty ok. you need to have a oauth client, pretty sure there is one out there for android

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: