18

I would like to mockup the RestClient class for test purposes

public class DataServices : IDataServices
{
    private readonly IRestClient _restClient;


    public DataServices(IRestClient restClient)
    {
        _restClient = restClient;
    }

    public async Task<User> GetUserByUserName(string userName)
    {
        User user = null;

        // create a new request
        var restRequest = new RestRequest("User", Method.GET);
        // create REST parameters
        restRequest.AddParameter("userName", userName, ParameterType.QueryString);
        // execute the REST request
        var restResponse = await _restClient.Execute<User>(restRequest);
        if (restResponse.StatusCode.Equals(HttpStatusCode.OK))
        {
            user = restResponse.Data;
        }
        return user;
    }

}

My test class :

[TestClass]
public class DataServicesTest
{
    public static IRestClient MockRestClient<T>(HttpStatusCode httpStatusCode, string json)
    {
        var mockIRestClient = new Mock<IRestClient>();
        mockIRestClient.Setup(x => x.Execute<T>(It.IsAny<IRestRequest>()))
          .Returns(new RestResponse<T>
          {
              Data = JsonConvert.DeserializeObject<T>(json),
              StatusCode = httpStatusCode
          });
        return mockIRestClient.Object;
    }

    [TestMethod]
    public async void GetUserByUserName()
    {
        var dataServices = new DataServices(MockRestClient<User>(HttpStatusCode.OK, "my json code"));
        var user = await dataServices.GetUserByUserName("User1");
        Assert.AreEqual("User1", user.Username);
    }
}

But I can't instantiate the RestResponse object, I've the following error:

.Returns(new RestResponse<T>
{
    Data = JsonConvert.DeserializeObject<T>(json),
    StatusCode = httpStatusCode
});

Cannot access protected internal constructor 'RestResponse' here.

How can I workaround this ? I'm using the FubarCoder.RestSharp nuget package on a Xamarin portable Library.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
Florian SANTI
  • 531
  • 1
  • 5
  • 13

3 Answers3

25

Mock IRestResponse<T> and return that

public static IRestClient MockRestClient<T>(HttpStatusCode httpStatusCode, string json) 
    where T : new() {
    var data = JsonConvert.DeserializeObject<T>(json)
    var response =  new Mock<IRestResponse<T>>();
    response.Setup(_ => _.StatusCode).Returns(httpStatusCode);
    response.Setup(_ => _.Data).Returns(data);

    var mockIRestClient = new Mock<IRestClient>();
    mockIRestClient
      .Setup(x => x.Execute<T>(It.IsAny<IRestRequest>()))
      .ReturnsAsync(response.Object);
    return mockIRestClient.Object;
}

The test should also be updated to be async as well

[TestMethod]
public async Task GetUserByUserName() {
    //Arrange
    var client = MockRestClient<User>(HttpStatusCode.OK, "my json code");
    var dataServices = new DataServices(client);
    //Act
    var user = await dataServices.GetUserByUserName("User1");
    //Assert
    Assert.AreEqual("User1", user.Username);
}
Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • @Nkosi I tried to use your method and I get following error: 'T' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'RestClient.Execute(RestRequest)'. Do you have an idea why I am getting this? – alminh Aug 09 '17 at 12:44
  • @alminh As the error message explains, chances are that you are using a type that is abstract. – Nkosi Aug 09 '17 at 12:53
  • 1
    Thank you for the response. I needed to add constraint where T : new() on the MockRestClient method. It works fine now. – alminh Aug 09 '17 at 13:45
  • @alminh you are correct. I reviewed the source code on Github and realized that the constraint was missing. I've updated answer to reflect that change. – Nkosi Aug 09 '17 at 14:38
2

I didn't find any great answers so I ended up writing a helper library. I published it to NuGet - MoqRestSharp.Helpers. This project is aimed to help unit test RestSharp as it extends Mock so this helped me test my RestSharp requests and response error handling.

It uses Moq

Feedback is always welcome!

William Zink
  • 189
  • 4
  • 15
2

Complete solution

using Moq;
using Newtonsoft.Json;
using NUnit.Framework;
using RestSharp;
using System.Net;

namespace RestMockTest
{
    public class Tests
    {
        [Test]
        public void Test1()
        {
            var client = MockRestClient<User>(HttpStatusCode.OK, "{\"Name\":\"User1\"}");
            var restRequest = new RestRequest("api/item/", Method.POST);
            var restResponse = client.Execute<User>(restRequest);

            var user = restResponse.Data;

            Assert.AreEqual("User1", user.Name);
        }

        public static IRestClient MockRestClient<T>(HttpStatusCode httpStatusCode, string json)
            where T : new()
        {
            var data = JsonConvert.DeserializeObject<T>(json);
            var response = new Mock<IRestResponse<T>>();
            response.Setup(_ => _.StatusCode).Returns(httpStatusCode);
            response.Setup(_ => _.Data).Returns(data);

            var mockIRestClient = new Mock<IRestClient>();
            
            mockIRestClient
              .Setup(x => x.Execute<T>(It.IsAny<IRestRequest>()))
              .Returns(response.Object);
            
            return mockIRestClient.Object;
        }
    }

    public class User
    {
        public string Name { get; set; }
    }
}