Can not instantiate proxy of class: System.Net.HttpWebRequest. Could not find a parameterless constructor

Viewed 426

I am upgrading my C# function app from .net 3.1 to 6.0`.

When I run my test cases, I found that, 1 of my test case failed with the below error.

Castle.DynamicProxy.InvalidProxyConstructorArgumentsException : Can not instantiate proxy of class: System.Net.HttpWebRequest. Could not find a parameterless constructor.

Basically, I am trying to mock HttpWebRequest and below is my piece of code for that.

var httpWebRequest = new Mock<HttpWebRequest>();

It is working fine in .Net 3.1. I am using Moq version 4.16.1 in both the projects.

2 Answers

I spent a fair bit of time when .Net 6 was initially released getting my Unit Test suite established. Here's how I do it using the same Moq version 4.16.1:

The Unit Tests get a Moq HttpClientFactory from the BaseClass:

public class UnitTests : BaseUnitTest
{
[Fact]
public async Task Should_Return_GetSomethingAsync()
{
    // Arrange
    IHttpClientFactory httpClientFactory = base.GetHttpClientFactory(new Uri("ExternalWebsiteUrlToMockTheResponse"), new StringContent("A Mock Response JSON Object"));
    YourService yourService = new YourService(httpClientFactory);

    // Act
    Something something = yourService.GetSomethingAsync().Result;

    // Assert
    Assert.IsType<Something>(Something);
    //..
}

In a BaseUnitTest.cs Class:

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Moq;
using Moq.Protected;

public class BaseUnitTest
{
public IHttpClientFactory GetHttpClientFactory(Uri uri, StringContent content, HttpStatusCode statusCode = HttpStatusCode.OK)
{
    Mock<HttpMessageHandler> httpMsgHandler = new Mock<HttpMessageHandler>();
    httpMsgHandler.Protected().Setup<Task<HttpResponseMessage>>("SendAsync", new object[2]
    {
        ItExpr.IsAny<HttpRequestMessage>(),
        ItExpr.IsAny<CancellationToken>()
    }).ReturnsAsync(new HttpResponseMessage
    {
        StatusCode = statusCode,
        Content = content
    });
    HttpClient client = new HttpClient(httpMsgHandler.Object);
    client.BaseAddress = uri; 
    Mock<IHttpClientFactory> clientFactory = new Mock<IHttpClientFactory>();
    clientFactory.Setup((IHttpClientFactory cf) => cf.CreateClient(It.IsAny<string>())).Returns(client);

    return clientFactory.Object;
}

Your Service Class or Controller:

public class YourService : IYourService
{
    private readonly IHttpClientFactory _clientFactory;
    private readonly HttpClient _client;
    public YourService(IHttpClientFactory clientFactory)
    {          
        _clientFactory = clientFactory;
        _client = _clientFactory.CreateClient("YourAPI");
    }

    public async Task<Something> GetSomethingAsync()
    {
        using (var request = new HttpRequestMessage(HttpMethod.Post, _client.BaseAddress))
        {
            request.Content = new StringContent($@"{{""jsonrpc"":""2.0"",""method"":""Something"",""params"": [""{SomethingHash}""],""id"":1}}");

            using (var response = await _client.SendAsync(request))
            {
                //System.Diagnostics.Debug.WriteLine(response?.Content.ReadAsStringAsync()?.Result);

                if (response.IsSuccessStatusCode)
                {
                    using (var responseStream = await response.Content.ReadAsStreamAsync())
                    {
                        var options = new JsonSerializerOptions { IncludeFields = true };
                        var something = await JsonSerializer.DeserializeAsync<Something>(responseStream, options);
                        // Check if the transactions from the address we're looking for...
                        if (something != null)
                        {
                            if (something.result?.from == address)
                            {
                                return something;
                            }
                 } } }
                else {
                    string exceptionMsg = $"Message: {response.Content?.ReadAsStringAsync()?.Result}";
                    throw new YourGeneralException(response.StatusCode, exceptionMsg);
                }
            }
        }
        return null;
    }
}

In your Program.cs

builder.Services.AddHttpClient("YourAPI", c =>
{
    c.BaseAddress = new Uri("ExternalWebsiteUrlToMockTheResponse");
    c.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    c.DefaultRequestHeaders.UserAgent.TryParseAdd("Your Agent");
});

You can expand the BaseUnitTest.ccs class to have chained tests as well.

Both HttpWebRequest constructors are obsolete and should not be used. You have to use the static function "Create" to create a new instance of the HttpWebRequest class:

HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create("http://www.contoso.com/");

To solve your issue, use the HttpClient class instead. This class has a parameterless constructor.

Related