使用httpclient调用Web API的单元测试MVC操作

时间:2015-02-02 04:40:44

标签: model-view-controller asp.net-web-api moq

请参阅下面的代码。使用内存托管httpclient,并将httpclient对象传递给控制器​​以便单元测试操作方法。但我得到了#34;内部服务器错误" HttpResponseMessage响应时的ReasonPhrase = _httpClient.GetAsync。请帮帮我,这是正确的方法吗?

    private readonly HttpClient _httpClient;
    public SecurityMfMvcController(HttpClient httpClient)
    {
        this._httpClient = httpClient;
    }
    [HttpGet]
    public ActionResult GetSecuritiesMfs()
    {
        try
        {                
            _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            HttpResponseMessage response =
                _httpClient.GetAsync(ConfigurationManager.AppSettings["ApiUrl"] + "SecuritiesWebApiMf").Result;
            response.EnsureSuccessStatusCode();
            List<SecurityMutualFundDto> list =
            response.Content.ReadAsAsync<List<SecurityMutualFundDto>>().Result;
            return View("SecuritiesMf", list);

        }
        catch (Exception ex)
        {
            return View("Error", ex.Message);
        }

    }
//Unit Test Method for this Action
 [Test]
    public void TestActionGetSecuritiesMfs()
    {
        var config = new HttpConfiguration()
        {
            IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always
        };
        //use the configuration that the web application has defined
        WebApiConfig.Register(config);
        HttpServer server = new HttpServer(config);
        //create a client with a handler which makes sure to exercise the formatters
        using (var client = new HttpClient(new InMemoryHttpContentSerializationHandler(server)))
        {
            System.Uri uri = new System.Uri("http://localhost:55893/api/");
            client.BaseAddress = uri;
            var controller = new SecurityMfMvcController(client);
            var result = controller.GetSecuritiesMfs();
            Assert.IsNotNull(result);
        }

    }
//MessageHandler
public class InMemoryHttpContentSerializationHandler : DelegatingHandler
{
    public InMemoryHttpContentSerializationHandler(HttpMessageHandler innerHandler)
        : base(innerHandler)
    {
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        request.Content = await ConvertToStreamContentAsync(request.Content);

        HttpResponseMessage response = await base.SendAsync(request, cancellationToken);

        response.Content = await ConvertToStreamContentAsync(response.Content);

        return response;
    }

    private async Task<StreamContent> ConvertToStreamContentAsync(HttpContent originalContent)
    {
        if (originalContent == null)
        {
            return null;
        }

        StreamContent streamContent = originalContent as StreamContent;

        if (streamContent != null)
        {
            return streamContent;
        }

        MemoryStream ms = new MemoryStream();

        await originalContent.CopyToAsync(ms);

        // Reset the stream position back to 0 as in the previous CopyToAsync() call,
        // a formatter for example, could have made the position to be at the end
        ms.Position = 0;

        streamContent = new StreamContent(ms);

        // copy headers from the original content
        foreach (KeyValuePair<string, IEnumerable<string>> header in originalContent.Headers)
        {
            streamContent.Headers.TryAddWithoutValidation(header.Key, header.Value);
        }

        return streamContent;
    }
}

2 个答案:

答案 0 :(得分:1)

您可以模拟您的http请求管道并测试您的操作:

  var mockHttpRequest = new Mock<HttpRequestMessage>(new object[] {new HttpMethod("GET"), "www.someuri.com"});
  var mockHttpConfig = new Mock<HttpConfiguration>();
  var mockRouteData = new Mock<IHttpRouteData>();

  var mockHttpContext =
    new Mock<HttpControllerContext>(new object[]
                                      {mockHttpConfig.Object, mockRouteData.Object, mockHttpRequest.Object});

然后使用以下值设置控制器对象:

var controller = new YourController();
controller.ControllerContext = mockHttpContext.Object;
controller.Request = controller.ControllerContext.Request;
response = controller.SecuritiesMF();

您可以按照以下方式检查您的回复:

Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);

答案 1 :(得分:1)

我得到了它的工作,如果有任何错误,请纠正我。我必须创建一个如下所示的“FakeHttpMessageHandler”和内容类型,以匹配应用程序/ json内容类型的System.Net.Http.StreamContent。下面的代码正在使用httpclient调用WebAPI来单元测试mvc动作方法。但是我需要仔细检查这是否是单元测试的正确方法,将进一步审查。

[Test]
    public void TestActionMethodSelectByIdUsingFakeHandler()
    {
        var uobj = new UnitTestForApiController();
        var testobj= uobj.GetsecuritiesMfsList();
        MemoryStream stream = new MemoryStream();
        IFormatter formatter = new BinaryFormatter();
        formatter.Serialize(stream, testobj);
        var response = new HttpResponseMessage(HttpStatusCode.OK) 
        {Content = new StreamContent(stream)};

        using (var httpClient = new HttpClient(new FakeHandler
        {
            Response = response,
            InnerHandler = new HttpClientHandler()
        }))
        {
            System.Uri uri = new System.Uri("http://localhost:55893/api/");
            httpClient.BaseAddress = uri;
            var controller = new SecuritiesMfMvcController(httpClient);
            var result = controller.Select(2155) as ViewResult;
            Assert.IsNotNull(result);
            Assert.AreEqual(result.ViewName,"Select");
            Assert.AreEqual(result.Model, testobj.FirstOrDefault());

        }

// FakeHandler类如下所示

public class FakeHandler : DelegatingHandler
{
    public HttpResponseMessage Response { get; set; }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
                                                CancellationToken cancellationToken)
    {
        return Task.Factory.StartNew(() => Response, cancellationToken);
    }
}

//We can also have logic for abstracting appropriate StreamContent Creation into FakeContent class like below:
public class FakeHttpContent : HttpContent
{
    public object Content { get; set; }

    public FakeHttpContent(object content)
    {
        Content = content;
    }

    protected async override Task SerializeToStreamAsync(Stream stream,
        TransportContext context)
    {
        MemoryStream ms = new MemoryStream();
        IFormatter formatter = new BinaryFormatter();
        formatter.Serialize(ms, Content);
        await ms.CopyToAsync(stream);
    }

    protected override bool TryComputeLength(out long length)
    {
        length = Content.ToString().Length;
        return true;
    }
}
相关问题