为“private static readonly”字段创建存根

3
由于 不当实例化问题,建议创建一个private static readonlyHttpClient实例。
由于时间不足,我已经将mocked客户端注入到测试方法中,并将client作为参数传入。
问题是如何简单地将mock注入到SingleHttpClientInstanceControllerprivate static readonly HttpClient字段中?

4
你应该使用一个IoC容器,并配置它始终传递一个单一的实例。 - SLaks
需要一些代码。 - hellboy
了解IoC容器。具体细节取决于您如何构建代码。 - SLaks
1
只需摆脱readonly限制。有许多软件反模式需要放弃,以使其可测试。 - hoodaticus
2
您的选择是:1)使用某些抽象而不是直接使用该字段,或2)购买昂贵的解决方案,如Microsoft Fakes(VS Ultimate)或JustMock。 - Stephen Cleary
1个回答

4

如何简单地将mock注入到SingleHttpClientInstanceControllerprivate static readonly HttpClient字段中?

答案:没有简单的方法。

建议:

通过访问器来抽象资源

public interface IHttpClientAccessor {
    HttpClient HttpClient { get; }
}

并将其注入到依赖的控制器中。
public class SingleHttpClientInstanceController : ApiController {
    private readonly HttpClient HttpClient;

    public SingleHttpClientInstanceController(IHttpClientAccessor httpClientAccessor) {
        HttpClient = httpClientAccessor.HttpClient;
    }

    // This method uses the shared instance of HttpClient for every call to GetProductAsync.
    public async Task<Product> GetProductAsync(string id) {
        var hostName = HttpContext.Current.Request.Url.Host;
        var result = await HttpClient.GetStringAsync(string.Format("http://{0}:8080/api/...", hostName));
        return new Product { Name = result };
    }
}

同样的操作也应该用于访问HttpContext,这是最近在Asp.Net-Core中引入的IHttpContextAccessor

IHttpClientAcessor的实现可以像这样:

public class HttpClientAccessor : IHttpClientAccessor {
    static readonly Lazy<HttpClient> client = new Lazy<HttpClient>(() => new HttpClient());
    public HttpClient HttpClient { get { return client.Value; } }
}

现在,为了测试,您可以注入依赖项的模拟。

如果使用DI容器,请记得将访问者也注册为单例。


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