Trying to mock an IRestClient for testing my ApiService class.

5,725 views
Skip to first unread message

Jussy

unread,
Apr 8, 2012, 7:12:45 AM4/8/12
to rest...@googlegroups.com
Hi folks,

Problem: I'm not sure what I exactly have to mock, when mocking an IRestClient so I actually have some response.Data returned.

Details:

In my simple MonoTouch project, I'm trying to test my ApiService class, which consumes a 3rd party API (lets pretend it's Twitter).
As such, I want to make sure that my code which does stuff with the deserialized json, does work. Likewise, I need to make sure that my code handles unexpected API errors (twitter is down or offline or there's a network issue, etc. etc.).

So - instead of hitting Twitter each time .. and also testing for those unexpected error scenario's, I'm trying to Mock the IRestClient and setting up various success and failure scenario's.

So, I've made sure my ApiService takes an optional dependency of an IRestClient. If one is provided, use that. Otherwise, create a new instance.

public static IRestClient MockRestClient(HttpStatusCode httpStatusCode, string json)
{
    var mockIRestClient = new Mock<IRestClient>();
    mockIRestClient.Setup(x => x.Execute<RootObject>(It.IsAny<IRestRequest>()))
        .Returns(new RestResponse<RootObject>
                    {
                        Content = json, // NOTE: can be null (eg. bad result).
                        StatusCode = httpStatusCode
                    });
    return mockIRestClient.Object;
}

public class MyApiService
{
    public MyApiService(IRestClient restClient)
    {
        _restClient = restClient;
    }

    public IList<TwitterStatus> GetStatuses()
    {
        var restClient = _restClient ?? new RestClient();
        ......
        var response = restClient.Execute<RootObject>(restRequest);

       if (response.StatusCode == HttpStatusCode.OK && response.Data != null)
       {
           // Do some stuff with deserialized Data
           foreach(var item on response.Data)
           {
               twitterStatuses.Add(new TwitterStatus(item.User, item.Subject, item.Whatever));
           }
       }
    }
}

And that all works great ... except the Data is null :( I'm making the assumption that when i Mock the Content property, that somehow the internal magic also creates the Data property, instead of me having to also mock that property.

So - do we need to mock that out or is there some trick that we can do, so we basically mock out the content result and the stock RestSharp code grabs that, deserializes and sets the Data?

thank :)

-Jussy-

John Sheehan

unread,
Apr 9, 2012, 7:25:50 PM4/9/12
to rest...@googlegroups.com
I'm not too familiar with mocking, but Content pulls the data from RawBytes. Can you translate the content to bytes and set that instead?

Andrew Young

unread,
Apr 9, 2012, 8:07:22 PM4/9/12
to rest...@googlegroups.com
IRestClient.Execute() returns an IRestResponse. You should be returning a mock of IRestResponse rather than newing up the real RestResponse.

Once you mock one thing you have to mock everything.

Jussy

unread,
Apr 10, 2012, 3:53:27 AM4/10/12
to rest...@googlegroups.com
Hi gents.
i'm still trying to get this to work :blush:

mocking the RawBytes does set the Content .. so that's fine. but doesn't help me.

Looking at the source code, i saw where the Data property is defined: https://github.com/restsharp/RestSharp/blob/master/RestSharp/RestResponse.cs#L142

But I can't figure out what actually 'sets't that property, etc. Can you guys provide some clues to how/when that property is set?

Jussy

unread,
Apr 10, 2012, 3:59:28 AM4/10/12
to rest...@googlegroups.com
Just after I posted that, It hit me where to look.


this RestClient class sets that when it Executes, of course :P

@AYoung -> why do u suggest I mock the IRestResponse .. when i actually want a propery instance of that? What i'm hijacking is the rest client and how i don't really go outside/to the interwebs ... but pretend i do, via mocking...

Andrew Young

unread,
Apr 10, 2012, 12:33:14 PM4/10/12
to rest...@googlegroups.com
I'm suggesting that you mock the response as well because (I believe) mocking is about blackbox testing. It should make as little assumptions about external code as possible.

Jussy

unread,
Apr 11, 2012, 7:16:46 AM4/11/12
to rest...@googlegroups.com
FWIW (and to maybe help other newbies) this is what i've done :-

(NOTE: Using StructureMap for my mocking library)

// Arrange.
var mockIRestClient = new Mock<IRestClient>();
mockIRestClient.Setup(x => x.Execute<MyRootObject>(It.IsAny<IRestRequest>()))
    .Returns(new RestResponse< MyRootObject >
                {
                    StatusCode = HttpStatusCode.OK,
                    Data = null,
                    RawBytes =
                        Encoding.UTF8.GetBytes(
                            "<?xml version=\"1.0\" encoding=\"UTF-8\"?><error code=\"100\" description=\"Incorrect user credentials\"/>")
                });

or...

// Arrange.
var mockIRestClient = new Mock<IRestClient>();
mockIRestClient.Setup(x => x.Execute<MyRootObject>(It.IsAny<IRestRequest>()))
    .Returns(new RestResponse< MyRootObject >
                {
                    StatusCode = HttpStatusCode.OK,
                    Data = new MyRootObject { ... whatever ... }
                });

or ...

// Arrange.
var mockIRestClient = new Mock<IRestClient>();
mockIRestClient.Setup(x => x.Execute<MyRootObject>(It.IsAny<IRestRequest>()))
    .Returns(new RestResponse< MyRootObject >
                {
                    StatusCode = HttpStatusCode.InternalServerError,
                    ErrorMessage = "some error message"
                })

And depending on which scenario I'm testing, I pass in the mockIRestClient.Object() into the api service i want to test.

eg.

// More arranging..
var apiService = new ApiService(... whatever ..., mockIRestClient.Object());

// Act.
var result = apiService.GetWhatever(...);

// Assert.
Assert.NotNull(result);
... whatever ...

cheers :)
Reply all
Reply to author
Forward
0 new messages