如何在单元测试中模拟RestSharp便携式库

18

我想为测试目的创建RestClient类的模拟版本

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;
    }

}

我的测试类:

[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);
    }
}

但是我无法实例化RestResponse对象,出现以下错误:

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

无法在此处访问受保护的内部构造函数'RestResponse'。

我该如何解决这个问题?我正在Xamarin可移植库上使用FubarCoder.RestSharp nuget包。


模拟 IRestResponse<T> 并返回它。 - Nkosi
3个回答

25

模拟 IRestResponse<T> 并返回

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;
}

测试也应该更新为异步

[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 我尝试使用你的方法,但是我遇到了以下错误:'T' 必须是一个非抽象类型,并且必须具有公共的无参数构造函数,才能将其用作泛型类型或方法 'RestClient.Execute<T>(RestRequest)' 的参数 'T'。你知道我为什么会遇到这个问题吗? - alminh
@alminh 如错误信息所解释的那样,很有可能您正在使用一个抽象类型。 - Nkosi
1
谢谢您的回复。我需要在MockRestClient方法上添加T:new()约束。现在它运行得很好。 - alminh
@alminh 您说得对。我在Github上查看了源代码,意识到约束条件缺失。我已经更新了答案以反映这种变化。 - Nkosi

2
我没有找到很好的答案,所以最终编写了一个帮助库。我将它发布到了NuGet - MoqRestSharp.Helpers。该项目旨在帮助单元测试RestSharp,因为它扩展了Mock,因此这有助于我测试我的RestSharp请求和响应错误处理。
它使用Moq。 欢迎您提供反馈!

2

完整解决方案

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; }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接