Mocking the response stream in HttpWebResponse using Moq - c#

I'm using Moq to mock HttpWebResponse for unit testing. I created a mock class that inherits from the class I'm trying to test and I'm overriding the method that returns the HttpWebResponse. I want to write a JSON string to the response stream from the unit test but I get an ArgumentException when trying to read the stream saying "Stream was not readable".
Here is what I have:
public class ParentClass
{
private string ProcessResponse(HttpWebResponse response)
{
string json = String.Empty;
using (var streamReader = new StreamReader(response.GetResponseStream())) //exception here
{
json = streamReader.ReadToEnd();
}
return json;
}
//other stuff
}
public class MockClass : ParentClass
{
public Stream responseStream = new MemoryStream();
public void WriteJson(string json)
{
using(var writer = new StreamWriter(responseStream))
{
writer.Write(json);
}
}
protected override HttpWebResponse GetResponse(HttpWebRequest request)
{
var response = new Mock<HttpWebResponse>();
response.Setup(r => r.GetResponseStream()).Returns(responseStream);
return response.Object;
}
}

The problem seemed to be with the using statement. Here are the changes I made:
public void WriteJson(string json)
{
var jsonBytes = Encoding.UTF8.GetBytes(json);
responseStream.Write(jsonBytes, 0, jsonBytes.Length);
responseStream.Seek(0, SeekOrigin.Begin);
}

It's safer to use an overload of StreamWriter which leaves the underlying stream open:
public StreamWriter(Stream stream, Encoding encoding, int bufferSize, bool leaveOpen)

Related

How to Deserialize the current class

I do not know if this is even possible but let's suppose I have a class:
[Serializable]
public class Test
{
//Properties and functions would go here.
public void SaveClass(string FilePath)
{
System.IO.Stream stream = System.IO.File.Create(FilePath);
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
binaryFormatter.Serialize(stream, this);
stream.Close();
}
public void LoadClass(string FilePath)
{
System.IO.Stream stream = System.IO.File.OpenRead(FilePath);
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
this = binaryFormatter.Deserialize(stream); //It returns an error saying that 'this' is readonly.
stream.Close();
}
}
Now I want to be able to Save and Load the class. The SaveClass is working fine, but the LoadClass returns an error, because I can not assign anything to this. Is there a way that I could load the class from a file, or is this impossible.
Make LoadClass static, something like:
public static Test LoadClass(string FilePath)
{
System.IO.Stream stream = System.IO.File.OpenRead(FilePath);
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
var newTest = (Test)binaryFormatter.Deserialize(stream);
stream.Close();
return newTest;
}

Accessing the same files from multiple tasks

I have many files on disk that I need to read and deserialize, If i try to access these files using a streamreader from multiple tasks I get the following exception:
System.ObjectDisposedException: Cannot access a disposed object
System.Runtime.InteropServices.SafeHandle.DangerousReleaseInternal(bool dispose)SafeHandle.cs:193
System.Runtime.InteropServices.SafeHandle.DangerousRelease()SafeHandle.cs:142
System.IO.FileStream.Dispose(bool disposing)FileStream.cs:913
System.IO.IsolatedStorage.IsolatedStorageFileStream.Dispose(bool disposing)IsolatedStorageFileStream.cs:250
System.IO.Stream.Close()stream.cs:248
System.IO.StreamReader.Dispose(bool disposing)streamreader.cs:296
System.IO.TextReader.Dispose()textreader.cs:78
System.IO.TextReader.Dispose()(wrapper remoting-invoke-with-check)
.FileServices.StreamReaderWrapper.Dispose()
.FileServices.IsolatedSerializer.<DeserializeAsync>d__9<T>.MoveNext()
Here is the code:
public async Task<T> DeserializeAsync<T>(string path)
{
T result = default(T);
if (!_fileRepository.FileManager.FileExists(path)) { return result; }
using (var streamReader = _streamReader.GetNew(_fileRepository.FileManager.OpenFile(
path, FileMode.Open, FileAccess.Read, FileShare.Read)))
{
var contents = await streamReader.ReadToEndAsync();
result = _jsonSerializer.DeserializeFromString<T>(contents, Encoding.UTF8);
streamReader.Dispose();
}
return result;
}
What am I doing wrong here?
/// <summary>
/// Wrapper to allow testing with StreamReader
/// </summary>
public class StreamReaderWrapper : IStreamReader
{
private StreamReader _streamReader;
public void Dispose()
{
if (_streamReader != null)
{
_streamReader.Dispose();
_streamReader = null;
}
}
public IStreamReader GetNew(Stream stream)
{
Dispose();
_streamReader = new StreamReader(stream);
return this;
}
public string ReadToEnd()
{
return _streamReader.ReadToEnd();
}
public Task<string> ReadToEndAsync()
{
return _streamReader.ReadToEndAsync();
}
}
You are calling Dispose twice. The using statement will dispose your streamReader variable automatically after exiting the code block. But you are also explicitly calling streamReader.Dispose();
Also, your StreamReaderWrapper.GetNew() should just return a new instance of the wrapper, otherwise threads will step on each other's toes
I think you can't access the "getNew" function, as you already disposed the object..
from your code:
using (var streamReader = _streamReader.GetNew(_fileRepository.FileManager.OpenFile(
who's "_streamReader"? an instance of the wrapper or the wrapped reader?

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
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);
}
}
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.

Is there a way to have my serialization method be more modular?

I have a method I am using to to work with a Json response. Since this is part of a harness and I am going to be creating a number of different data objects is it possible to make this more generic so I don't have to create same code for each different data object I create.
[DataContract]
class Stats
{
[DataMember]
public string StatusCode {get;set;}
[DataMember]
public int ProspectCount {get;set;}
[DataMember]
public int MessageCount {get;set;}
[DataMember]
public int NewListingCount {get;set;}
[DataMember]
public int ReminderCount {get;set;}
[DataMember]
public int MyListingCount {get;set;}
[DataMember]
public int OfficListingCount {get;set;}
}
public static Stats SendRequest(string requestUrl)
{
try
{
HttpWebRequest request = WebRequest.Create(requestUrl) as HttpWebRequest;
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
if (response.StatusCode != HttpStatusCode.OK)
throw new Exception(String.Format(
"Server error (HTTP {0}: {1}).",
response.StatusCode,
response.StatusDescription));
DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(Stats));
object objResponse = jsonSerializer.ReadObject(response.GetResponseStream());
Stats jsonResponse
= objResponse as Stats;
return jsonResponse;
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return null;
}
}
I essentially want to be able to create a second and third data contract without having to recreate the SendRequest method.
Two options:
1: Make the SendRequest method the only static method in another class and have every object that needs it call it like this:
RequestSender.SendRequest(requestUrl).
2: Make this and the other classes you have to write extend a superclass that contains the SendRequest(String requestUrl) method so that they have access to that same method via inheritance.
Would a generic method work? The signature might look like this:
public static T SendRequest<T>(string requestUrl) where T : class
In the method body you would replace Stats with T.
Usage:
Stats response = RequestSender.SendRequest<Stats>("some URL");
OtherClass anotherResponse = RequestSender.SendRequest<OtherClass>("some other URL");
I ended up utilizing Json.NET for the serialization piece. This will do everything I needed it to. So now my method looks like:
public static string ProcessRequest(string requestUrl)
{
try
{
HttpWebRequest request = WebRequest.Create(requestUrl) as HttpWebRequest;
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
string responseContents;
if (response.StatusCode != HttpStatusCode.OK)
throw new Exception(String.Format(
"Server error (HTTP {0}: {1}).",
response.StatusCode,
response.StatusDescription));
Stream responseStream = response.GetResponseStream();
using(StreamReader readStream = new StreamReader(responseStream))
{
responseContents = readStream.ReadToEnd();
}
return responseContents;
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return null;
}
}
And the serialization component in another method is a simple one liner that takes the response as a string.:
Stats results = JsonConvert.DeserializeObject<Stats>(response);

Avoid fxcop error CA1004 in this case

I have a case where it is returning objects of type T. My code looks like this.
public static T GetObjectsFromWebRequest<T>(string urlPath) where T : class
{
T modelObjects;
try
{
//SaveServiceDataIntoTextFile(urlPath);
WebRequest request = WebRequest.Create(urlPath);
WebResponse ws = request.GetResponse();
StreamReader responseStream = new StreamReader(ws.GetResponseStream());
//Get the response of the webrequest into a string
string response = responseStream.ReadToEnd();
modelObjects = XMLSerializeDeserialize.ConvertXMLToModel<T>(response);
}
catch (Exception)
{
throw;
}
return modelObjects;
}
In this case I don't have any option but add a default parameter like
public static T GetObjectsFromWebRequest<T>(string urlPath, T a = null) where T : class
Is there any other way I can resolve this violation?
As suggested here, you could use an out parameter to convey your result:
public static void GetObjectsFromWebRequest<T>(string urlPath, out T objects) ...

Categories

Resources