Mar*_*tin 8 c# nunit moq mocking
我在nUnit中运行我的测试,通常我可以模拟出依赖项,然后返回某些值或抛出错误.
我有一个类作为内部HttpClient,我想测试该类,我有什么选择.
这是我的代码,它不完整,以免泛滥消息.正如您所看到的,我在内部使用HttpClient而不是作为依赖项注入.该类抛出了许多自定义异常,我想Moq这些,否则我需要传递真实的用户名和密码,这将给我提供我需要抛出异常的状态代码.
有人有想法吗?如果我不能模拟httpclient,那么我永远不会测试我的类,它会引发异常.
我是否真的必须将HttpClient更改为对构造函数的依赖?
public bool ItemsExist(string itemValue)
{
    var relativeUri = string.Format(UrlFormatString, itemValue.ToUpper());
    var uri = new Uri(new Uri(this.baseUrl), relativeUri);
    using (var client = new HttpClient())
    {
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", this.encodedCredentials);
        client.DefaultRequestHeaders.Accept.Add(
            new MediaTypeWithQualityHeaderValue("application/json"));
        var response = client.GetAsync(uri).Result;
        switch (response.StatusCode)
        {
            case HttpStatusCode.Unauthorized:
                // DO something here
                throw new CustomAuthorizationException();
            case HttpStatusCode.Forbidden:
                throw new CustomAuthenticationException();
        }
        return true;
ITm*_*eze 23
让我建议一个更简单的解决方案,而不需要抽象/包装httpclient,我相信与mocking框架完美配合.
您需要为假HttpMessageHandler创建一个类,如下所示:
public class FakeHttpMessageHandler : HttpMessageHandler
{
    public virtual HttpResponseMessage Send(HttpRequestMessage request)
    {
        throw new NotImplementedException("Rember to setup this method with your mocking framework");
    }
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        return Task.FromResult(Send(request));
    }
}
在实例化HttpClient时可以使用这样创建的HttpMessageHandler:
var msgHandler = new Mock<FakeHttpMessageHandler>() { CallBase = true };
var fakeclient = new HttpClient(msgHandler.Object);
你可以设置方法(这里使用Moq):
msgHandler.Setup(t => t.Send(It.Is<HttpRequestMessage>(
            msg =>
                    msg.Method == HttpMethod.Post &&
                    msg.RequestUri.ToString() == "http://test.te/item/123")))
                    .Returns(new HttpResponseMessage(System.Net.HttpStatusCode.NotFound));
您现在可以在必要时使用fakeclient.
dca*_*tro 11
你无法对它进行单元测试.就像你提到的那样:HttpClient是一个依赖项,因此它应该被注入.
就个人而言,我会创建自己的IHttpClient接口,实现方式HttpClientWrapper,包围System.Net.HttpClient.IHttpClient然后将作为依赖项传递给对象的构造函数.
如下,HttpClientWrapper不能进行单元测试.但是,我会编写几个集成测试来确保包装器编写得很好.
编辑:
IHttpClient不必是一个"有效"的接口HttpClient.它只需要一个适合您需求的界面.它可以有很多或只要你想一些方法.
想象一下:HttpClient允许你做很多事情.但是在你的项目中,你只是在调用GetAsync(uri).Result方法,没有别的.
在这种情况下,您将编写以下接口和实现:
interface IHttpClient
{
    HttpResponseMessage Get(string uri);
}
class HttpClientWrapper : IHttpClient
{
    private readonly HttpClient _client;
    public HttpClientWrapper(HttpClient client)
    {
        _client = client;
    }
    public HttpResponseMessage Get(string uri)
    {
        return _client.GetAsync(new Uri(uri)).Result;
    }
}
因此,正如我之前所说,界面只需满足您的需求.您不必环绕WHOLE HttpClient类.
显然,你会像这样moq你的对象:
var clientMock = new Mock<IHttpClient>();
//setup mock
var myobj = new MyClass(clientMock.object);
并创建一个实际的对象:
var client = new HttpClientWrapper(new HttpClient());
var myobj = new MyClass(client );
EDIT2
哦!而且别忘了IHttpClient还应该扩展IDisposable界面,非常重要!
| 归档时间: | 
 | 
| 查看次数: | 8199 次 | 
| 最近记录: |