jeudi 29 janvier 2015

How do Test HttpWebRequest Depended method?

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


Aucun commentaire:

Enregistrer un commentaire