如何模拟 RestSharp AddDefaultHeader 方法

How to mock RestSharp AddDefaultHeader method

我正在尝试对使用 RestSharp(版本 106.6.9)的方法进行单元测试:

public UserInfo GetUserInfo(string oauthToken)
{
    _restClient.AddDefaultHeader("Authorization", "Bearer " + oauthToken);

    var request = new RestRequest(_userInfoUrl);
    var response = _restClient.Execute<UserInfo>(request);
    if (!response.IsSuccessful)
    {
        throw new ApplicationException("Request for user info failed with HTTP status code " + response.StatusCode);
    }

    return response.Data;
}

这是我试过的:

[Test]
public void ShouldFailIfOAuthTokenExpired()
{
    var mockRestClient = new Mock<IRestClient>();
    mockRestClient.Setup(m => m.AddDefaultHeader("Authorization", "Bearer Some expired token"));
    mockRestClient.Setup(m => m.Execute(It.IsAny<IRestRequest>())).Returns(new RestResponse() { StatusCode = System.Net.HttpStatusCode.Unauthorized });

    var svc = new MyService(mockRestClient.Object, "my endpoint");

    Assert.Throws<ApplicationException>(() => svc.GetUserInfo("Some expired token"));
}

此代码已构建,但抛出运行时异常阻止我的测试工作:

System.NotSupportedException : Unsupported expression: m => m.AddDefaultHeader("Authorization", "Bearer Some expired token")
Extension methods (here: RestClientExtensions.AddDefaultHeader) may not be used in setup / verification expressions.

如果我的方法包含对 .AddDefaultHeader 的调用,我似乎无法测试我的方法。我考虑创建自己的模拟对象,但 IRestClient 接口需要许多方法。

关于如何测试我的方法有什么建议吗?

如果您想检查是否添加了默认 header,您可以使用 spy,如下所示:

    [Fact]
    public void Test()
    {
        var mock = new Mock<IRestClient>();
        var spy = new List<Parameter>();
        mock
            .Setup(m => m.DefaultParameters.Add(It.IsAny<Parameter>()))
            .Callback((Parameter p) => spy.Add(p));
        var instance = mock.Object;

        instance.AddDefaultParameter(new Parameter("Foo", "Bar", ParameterType.Cookie));

        Assert.Equal("Bar", spy.Single().Value);
    }

这使用 Moq.Callback 功能,将添加的 Parameter 添加到 spy

这是有效的,因为您可以在 RestSharpsource code 中看到此 extension method 调用 AddDefaultParameter,后者又将 Parameter 添加到 DefaultParameters:

restClient.DefaultParameters.Add(p);

本例使用xUnit作为测试运行器,其他应该是一样的

Moq 不模拟扩展方法。找出扩展方法访问的内容,这就是您模拟的内容。

该扩展方法的源代码可用并最终调用

/// <summary>
/// Add a parameter to use on every request made with this client instance
/// </summary>
/// <param name="restClient">The IRestClient instance</param>
/// <param name="p">Parameter to add</param>
/// <returns></returns>
public static IRestClient AddDefaultParameter(this IRestClient restClient, Parameter p)
{
    if (p.Type == ParameterType.RequestBody)
    {
        throw new NotSupportedException(
            "Cannot set request body from default headers. Use Request.AddBody() instead.");
    }

    restClient.DefaultParameters.Add(p);

    return restClient;
}

Source

因此,根据您需要访问的内容,restClient.DefaultParameters 就是需要模拟的内容。

如果实际上不需要任何实际功能,这只是为了避免空引用异常,则使用 SetupAllProperties

设置模拟以存根所有可用属性
//...

mockRestClient.SetupAllProperties();

//...