2

I have this class:

public class RestClient
{
    public RestClient() 
    { }

    protected virtual HttpWebRequest CreateHttpWebRequest(Uri uri)
    {
        return (HttpWebRequest)HttpWebRequest.Create(uri);
    }


    /// <summary>
    /// Perform a http POST request in order to push data to server
    /// </summary>
    /// <param name="uri">End Point Uri</param>
    /// <param name="data">Data to be transmitted</param>
    /// <returns></returns>
    /// 
    public long PostRequest(Uri uri,string data) 
    {

        try
        {
            HttpWebRequest request = CreateHttpWebRequest(uri); //(HttpWebRequest)HttpWebRequest.Create(uri);

            request.Method = "POST";
            request.ContentType = "application/json";

            System.Text.UTF8Encoding encoding = new UTF8Encoding();

            byte[] bytes = encoding.GetBytes(data);



            using (Stream requestStream = request.GetRequestStream())
            {
                //Transmit data
                requestStream.Write(bytes, 0, bytes.Length);
                requestStream.Flush();
                requestStream.Close();
            }



            //Get the Response from the server
            using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
            {
                if (response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.NoContent)
                {
                    throw new Exception(String.Format(
                       "Server error (HTTP {0}: {1}).",
                            response.StatusCode,
                                response.StatusDescription));
                }
            }


            return request.ContentLength;
        }
        catch (Exception e)
        {
            throw e;
        }

    }       

}

And would like to Unit test (using nunit) the PostRequest Method.

Doing some research, I could found some way to mock the HttpWebRequest in this post (Is it possible to mock out a .NET HttpWebResponse?) and a way to inject it into the class in this post (How to unit test a method with HttpWebRequest/Response dependencies).

However, when I tried to test my method I got this error:

System.InvalidCastException : Unable to cast object of type 'Castle.Proxies.IHttpWebRequestProxy' to type 'System.Net.HttpWebRequest'.

in this line of my test

client.HttpWebRequestFake = (HttpWebRequest)factory.Object.Create("http://127.0.0.1");

That is my test code:

public class TesableRestClient : RestClient
{
    public HttpWebRequest HttpWebRequestFake { get; set; }

    protected override HttpWebRequest CreateHttpWebRequest(Uri url)
    {
        if (HttpWebRequestFake != null)
            return HttpWebRequestFake;
        return base.CreateHttpWebRequest(url);
    }
}


[TestFixture]
public class TransferWebRequestTest
{
    [Test]
    public void TestPostResquest()
    {
        string expectedContent  = "Content";
        var expectedBytes = Encoding.UTF8.GetBytes(expectedContent);
        var responseStream = new MemoryStream();
        responseStream.Write(expectedBytes, 0, expectedBytes.Length);
        responseStream.Seek(0, SeekOrigin.Begin);

        var response = new Mock<IHttpWebResponse>();
        response.Setup(c => c.GetResponseStream()).Returns(responseStream);

        var request = new Mock<IHttpWebRequest>();
        request.Setup(c => c.GetResponse()).Returns(response.Object);

        var factory = new Mock<IHttpWebRequestFactory>();
        factory.Setup(c => c.Create(It.IsAny<string>()))
            .Returns(request.Object);

        TesableRestClient client = new TesableRestClient();
        client.HttpWebRequestFake = (HttpWebRequest)factory.Object.Create("http://127.0.0.1");

        // DoStuff call the url with a request and then processes the
        long bytesSent = client.PostRequest(new Uri("http://127.0.0.1"), expectedContent);
         Assert.AreEqual(expectedBytes, bytesSent);
}

The HttpWebRequest/Response is this:

public interface IHttpWebRequest
{
    // expose the members you need
    string Method { get; set; }
    string ContentType { get; set; }
    long ContentLength { get; set; }
    IHttpWebResponse GetResponse();
}

public interface IHttpWebResponse : IDisposable
{
    // expose the members you need
    HttpStatusCode StatusCode { get; }
    string StatusDescription { get;}
    Stream GetResponseStream();
}

public interface IHttpWebRequestFactory
{
    IHttpWebRequest Create(string uri);
}

// barebones implementation

public class HttpWebRequestFactory : IHttpWebRequestFactory
{
    public IHttpWebRequest Create(string uri)
    {
        return new WrapHttpWebRequest((HttpWebRequest)WebRequest.Create(uri));
    }
}

public class WrapHttpWebRequest : IHttpWebRequest
{
    private readonly HttpWebRequest _request;

    public WrapHttpWebRequest(HttpWebRequest request)
    {
        _request = request;
    }

    public string Method
    {
        get { return _request.Method; }
        set { _request.Method = value; }
    }

    public string ContentType
    {
        get { return _request.ContentType; }
        set { _request.ContentType = value; }
    }

    public long ContentLength
    {
        get { return _request.ContentLength; }
        set { _request.ContentLength = value; }
    }

    public IHttpWebResponse GetResponse()
    {
        return new WrapHttpWebResponse((HttpWebResponse)_request.GetResponse());
    }
}

public class WrapHttpWebResponse : IHttpWebResponse
{
    private HttpWebResponse _response;

    public WrapHttpWebResponse(HttpWebResponse response)
    {
        _response = response;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (_response != null)
            {
                ((IDisposable)_response).Dispose();
                _response = null;
            }
        }
    }

    public Stream GetResponseStream()
    {
        return _response.GetResponseStream();
    }

    public HttpStatusCode StatusCode
    {
        get { return _response.StatusCode; }
    }

    public string StatusDescription
    {
        get { return _response.StatusDescription; }
    }

}

Any idea of how I could solve this?

Thank you

Community
  • 1
  • 1
  • Read the error message, it tells you the problem. If you check your code, the class `WrapHttpWebRequest` is not of type `HttpWebRequest`. – Quality Catalyst Jan 30 '15 at 00:46

2 Answers2

1

I solved my issue doing the follow:

First, created a interface IHttpWebRequestFactory

public interface IHttpWebRequestFactory
{
    HttpWebRequest Create(string uri);
}

In the class that I want to test, I created the following methods:

protected virtual HttpWebRequest CreateHttpWebRequest(Uri uri)
    {
        return (HttpWebRequest)HttpWebRequest.Create(uri);
    }

    protected virtual HttpWebResponse GetHttpWebResponse(HttpWebRequest request)
    {
        return (HttpWebResponse)request.GetResponse();
    }

In my test file, I created a "Testable " class, that inherits from the class I really want to test and overrides the virtual methods:

 //Class Created to test the PostRequestMethod
public class TestableRestClient : RestClient
{
    public HttpWebRequest HttpWebRequestFake { get; set; }

    public string responseValue;

    protected override HttpWebRequest CreateHttpWebRequest(Uri url)
    {
        if (HttpWebRequestFake != null)
            return HttpWebRequestFake;
        return base.CreateHttpWebRequest(url);
    }

    protected override HttpWebResponse GetHttpWebResponse(HttpWebRequest request)
    {
        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        using (var streamReader = new StreamReader(request.GetResponse().GetResponseStream()))
        {
            responseValue = streamReader.ReadToEnd();
        }
        return base.GetHttpWebResponse(request);
    }
}

Then I used Moq to mock the behavior of methods I'm using in my class

 [TestFixture]
public class DMSTransferWebRequestTest
{
    [Test]
    public void TestPostResquest()
    {      

        string expected = "Content";

        //Prepare the Mocked Response Stream
        byte [] expectedBytes = Encoding.UTF8.GetBytes(expected);
        Stream responseStream = new MemoryStream();
        responseStream.Write(expectedBytes, 0, expectedBytes.Length);
        responseStream.Seek(0, SeekOrigin.Begin);

        //Prepare the Mocked Request Stream
        Stream requestStream = new MemoryStream();
        requestStream.Write(expectedBytes, 0, expectedBytes.Length);
        requestStream.Seek(0, SeekOrigin.Begin);

        //Mock the HttpWebResponse
        Mock<HttpWebResponse> response = new Mock<HttpWebResponse>();

        //Set the method GetResponseStream to return the Response Stream mocked
        response.Setup(c => c.GetResponseStream()).Returns(responseStream);
        response.Setup(c => c.StatusCode).Returns(HttpStatusCode.OK);

        //Set the method GetRequestStream to return the Request Stream mocked
        Mock<HttpWebRequest> request = new Mock<HttpWebRequest>();
        request.Setup(c => c.GetResponse()).Returns(response.Object);
        request.Setup(c => c.GetRequestStream()).Returns(requestStream);

        //Create a Object to mock the HttpWebRequest Create Method
        Mock<IHttpWebRequestFactory> factory = new Mock<IHttpWebRequestFactory>();
        factory.Setup(c => c.Create(It.IsAny<string>()))
            .Returns(request.Object);


        TestableRestClient client = new TestableRestClient();
        client.HttpWebRequestFake = factory.Object.Create("http://mytest");

        long actualBytes = client.PostRequest(new Uri("http://mytest"), expected);

        string actual = client.responseValue;


        Assert.AreEqual(expected, actual);

    }
}
0

Not really sure what you want to achieve, but this may help. The error message tells you the exact problem and gives you a hint what to do.

If you check your code, the class WrapHttpWebRequest is not of type HttpWebRequest. However, it holds an HttpWebRequest. These two steps solve the direct issue, but you may run into another issue. First, provide a property to the class WrapHttpWebRequest:

public HttpWebRequest HttpWebRequest { get { return _request; } }

Then change you failing code line to this:

client.HttpWebRequestFake = factory.Object.Create("http://127.0.0.1").HttpWebRequest;

I reckon though that it would be better to change the class WrapHttpWebRequest and inherit from 'HttpWebRequest' like this ...

public class WrapHttpWebRequest: HttpWebRequest, IHttpWebRequest

... and change its implementation accordingly.

Quality Catalyst
  • 6,531
  • 8
  • 38
  • 62
  • I am trying to test my method without an Http server running. I have googled but couold not find something that would work for me besides the two links I posted – Gabriel Augusto Jan 30 '15 at 01:04